# useAppClient

This hook provides access to the client context, including shared data, actions, navigation, and more.

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

const MyComponent = () => {
  const { data, navigate, showToast } = useAppClient();

  return (
    <div>
      <p>User: {data?.user?.name}</p>
      <button onClick={() => navigate({ path: '/home' })}>Home</button>
      <button onClick={() => showToast('Hello!', 'success')}>Greet</button>
    </div>
  );
};
```

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

The `useAppClient` hook returns an `AppClientContextState` object:

| Property                 | Type                                                  | Description                              |
| ------------------------ | ----------------------------------------------------- | ---------------------------------------- |
| `data`                   | `ApplicationData \| undefined`                        | Shared data from the shell               |
| `params`                 | `ApplicationParams \| undefined`                      | Parameters passed to plugin applications |
| `isLoading`              | `boolean`                                             | Whether the application data is loading  |
| `modalContext`           | `unknown`                                             | Context data for rich modals             |
| `locale`                 | `string`                                              | Current locale from the shell            |
| `navigate`               | `(payload) => void`                                   | Navigate within the shell                |
| `invokeAction`           | `(key, ...args) => Promise`                           | Invoke custom shell actions              |
| `showModalDialog`        | `(options) => boolean`                                | Show a modal dialog                      |
| `showConfirmationDialog` | `(options) => boolean`                                | Show a confirmation dialog               |
| `showToast`              | `(content, type) => boolean`                          | Show a toast notification                |
| `showErrorMessage`       | `(title, content) => boolean`                         | Show an error message                    |
| `showRichModal`          | `(path, context?, size?, closeIconColor?) => boolean` | Show a rich modal                        |
| `removeSearchParams`     | `(keys) => void`                                      | Remove URL search params                 |
| `setSearchParams`        | `(params) => void`                                    | Set URL search params                    |
| `onLocaleChange`         | `(callback) => () => void`                            | Subscribe to locale changes              |

### <mark style="color:red;">Accessing Shared Data</mark>

The `data` property contains the shared data from the shell:

```tsx
const UserInfo = () => {
  const { data, isLoading } = useAppClient();

  if (isLoading) {
    return <Spinner />;
  }

  return (
    <div>
      <h1>Welcome, {data?.user?.name}</h1>
      <p>Theme: {data?.theme}</p>
      <p>Language: {data?.locale}</p>
    </div>
  );
};
```

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

Request the shell to navigate to a different route:

```tsx
const NavigationExample = () => {
  const { navigate } = useAppClient();

  return (
    <div>
      <button onClick={() => navigate({ path: '/orders' })}>
        View Orders
      </button>
      <button onClick={() => navigate({ path: '/products?category=electronics' })}>
        Electronics
      </button>
    </div>
  );
};
```

### <mark style="color:red;">Invoking Custom Actions</mark>

Call custom actions defined in the shell:

```tsx
const ActionExample = () => {
  const { invokeAction } = useAppClient();

  const handleLogout = async () => {
    try {
      await invokeAction('performLogout');
    } catch (error) {
      console.error('Logout failed:', error);
    }
  };

  const handleFetchData = async () => {
    const result = await invokeAction('fetchUserData', userId);
    console.log('User data:', result);
  };

  return (
    <div>
      <button onClick={handleLogout}>Logout</button>
      <button onClick={handleFetchData}>Fetch Data</button>
    </div>
  );
};
```

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

#### showToast

Display a brief notification:

```tsx
const ToastExample = () => {
  const { showToast } = useAppClient();

  return (
    <div>
      <button onClick={() => showToast('Saved successfully!', 'success')}>
        Success
      </button>
      <button onClick={() => showToast('Something went wrong', 'error')}>
        Error
      </button>
      <button onClick={() => showToast('Please wait...', 'loading')}>
        Loading
      </button>
      <button onClick={() => showToast('', 'destroy')}>
        Clear All
      </button>
    </div>
  );
};
```

#### showConfirmationDialog

Display a confirmation dialog with callbacks:

```tsx
const ConfirmExample = () => {
  const { showConfirmationDialog } = useAppClient();

  const handleDelete = () => {
    showConfirmationDialog({
      title: 'Delete Item',
      content: 'Are you sure you want to delete this item?',
      onConfirm: () => {
        console.log('User confirmed deletion');
        deleteItem();
      },
      onCancel: () => {
        console.log('User cancelled');
      }
    });
  };

  return <button onClick={handleDelete}>Delete</button>;
};
```

#### showErrorMessage

Display an error message dialog:

```tsx
const ErrorExample = () => {
  const { showErrorMessage } = useAppClient();

  const handleError = (error: Error) => {
    showErrorMessage('Operation Failed', error.message);
  };

  return <button onClick={() => handleError(new Error('Test'))}>Show Error</button>;
};
```

#### showRichModal

Open a rich modal with another micro-frontend:

```tsx
const RichModalExample = () => {
  const { showRichModal } = useAppClient();

  const openProductDetail = (productId: string) => {
    showRichModal(
      `/products/${productId}`,           // path
      { productId, mode: 'view' },        // context
      { maxWidth: 800, maxHeight: '90vh' }, // size
      '#ffffff'                            // closeIconColor
    );
  };

  return (
    <button onClick={() => openProductDetail('prod-123')}>
      View Product
    </button>
  );
};
```

### <mark style="color:red;">URL Search Params</mark>

Manage URL search parameters:

```tsx
const SearchParamsExample = () => {
  const { setSearchParams, removeSearchParams, data } = useAppClient();

  const applyFilters = () => {
    setSearchParams({
      category: 'electronics',
      page: 1,
      limit: 20
    });
  };

  const clearFilters = () => {
    removeSearchParams(['category', 'page', 'limit']);
  };

  return (
    <div>
      <p>Current params: {JSON.stringify(data?.searchParams)}</p>
      <button onClick={applyFilters}>Apply Filters</button>
      <button onClick={clearFilters}>Clear Filters</button>
    </div>
  );
};
```

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

Access parameters passed to plugin applications:

```tsx
// Shell passes params via PluginRenderer
// <PluginRenderer placeholderId="product-widget" params={{ productId: '123' }} />

const PluginComponent = () => {
  const { params } = useAppClient();

  return (
    <div>
      <p>Product ID: {params?.productId}</p>
    </div>
  );
};
```

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

Access context data in rich modals:

```tsx
// When opened via showRichModal(path, context)
const ModalContent = () => {
  const { modalContext } = useAppClient();

  return (
    <div>
      <h1>Product Detail</h1>
      <p>ID: {(modalContext as any)?.productId}</p>
      <p>Mode: {(modalContext as any)?.mode}</p>
    </div>
  );
};
```

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

React to locale changes from the shell:

```tsx
import { useEffect } from 'react';
import { i18n } from '@akinon/akilocale/react';

const LocaleAwareComponent = () => {
  const { locale, onLocaleChange } = useAppClient();

  useEffect(() => {
    // Set initial locale
    i18n.changeLanguage(locale);

    // Subscribe to changes
    const unsubscribe = onLocaleChange((newLocale) => {
      i18n.changeLanguage(newLocale);
    });

    return unsubscribe;
  }, [locale, onLocaleChange]);

  return <div>Current locale: {locale}</div>;
};
```

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

#### 1. Handle Loading State

Always check `isLoading` before accessing `data`:

```tsx
const Component = () => {
  const { data, isLoading } = useAppClient();

  if (isLoading) {
    return <Loading />;
  }

  return <Content data={data} />;
};
```

#### 2. Optional Chaining for Data

Use optional chaining when accessing nested data:

```tsx
// ✅ Good
const userName = data?.user?.name;

// ❌ Bad - may throw
const userName = data.user.name;
```

#### 3. Error Handling for Actions

Wrap action invocations in try-catch:

```tsx
const handleAction = async () => {
  try {
    const result = await invokeAction('someAction', arg1, arg2);
    showToast('Success!', 'success');
  } catch (error) {
    showErrorMessage('Error', error.message);
  }
};
```

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

* Configuration - Configure your client application
* i18n - Internationalization
* API Reference - Complete API documentation


---

# 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/client-application/useappclient.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.
