> ## Documentation Index
> Fetch the complete documentation index at: https://docs.skyvexsoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# UI Module

> Building your plugin's user interface.

The UI module is a single React component exported as the default export from `src/ui/index.tsx`. The shell renders it in the main content area when a pilot selects your plugin in the sidebar.

## What the Shell Provides

The shell injects several libraries at runtime — you don't need to bundle them, and the build system externalises them automatically. Import them directly:

* `react`, `react-dom`
* `@tanstack/react-query`, `@tanstack/react-router`
* `@skyvexsoftware/stratos-sdk` (hooks, UI components, types, helpers)
* `sonner` (toast notifications)
* `socket.io-client`
* `maplibre-gl`, `react-map-gl/maplibre`

Anything else you import — `lucide-react`, your own utilities, third-party libraries — will be bundled into your plugin's `ui/index.js`.

## Using `usePluginContext()`

The primary way to access shell state from any component in your plugin:

```tsx theme={null}
import { usePluginContext } from "@skyvexsoftware/stratos-sdk";

function MyComponent() {
  const ctx = usePluginContext();

  // ctx.pluginId   — your plugin's ID string
  // ctx.auth       — { isAuthenticated, token, user }
  // ctx.airline    — { id, name, icao, logo_light, logo_dark, base_url, token } or null
  // ctx.config     — synchronous { get<T>(key, default?) }, scoped to your plugin
  // ctx.socket     — subscribe to your background module's ctx.ipc.send broadcasts
  // ctx.vaApi      — shared axios instance for the airline API (prefer useVaApi())
  // ctx.navigation — navigate within/between plugins and to shell routes
  // ctx.toast      — { success(), error(), info(), warning() }
  // ctx.logger     — { info(), warn(), error(), debug() }
}
```

`usePluginContext()` can be called in any component in your tree — not just the root. The context is provided by the `PluginShellProvider` that wraps your entire plugin.

## Auth

```tsx theme={null}
const { auth } = usePluginContext();

if (!auth.isAuthenticated || !auth.user) {
  return <p>Please log in to use this plugin.</p>;
}

// auth.user: PluginPilotUser — pilot profile (firstName, lastName, pilotID, rank, avatar, etc.)
// auth.token: string | null  — VA auth token for API calls
```

You can also use the convenience hook:

```tsx theme={null}
import { useShellAuth } from "@skyvexsoftware/stratos-sdk";

const { isAuthenticated, token, user } = useShellAuth();
```

### Calling the VA's API

For HTTP calls to the bound airline's API, use [`useVaApi()`](/sdk/hooks/use-va-api). It returns a pre-configured axios instance that attaches the bearer, sets the airline's `base_url`, and transparently refreshes the access token on `401`:

```tsx theme={null}
import { useVaApi } from "@skyvexsoftware/stratos-sdk";

const va = useVaApi();
const { data } = await va.get("/pilot/verify");
```

This is the renderer-side equivalent of [`ctx.airline.createClient()`](/sdk/background/context/airline) in background modules.

## Config

Read plugin settings declared in your manifest's `availableSettings`. Config access in the UI module is **synchronous** — values are pre-loaded when your plugin mounts:

```tsx theme={null}
const { config } = usePluginContext();

const welcomeMsg = config.get<string>("welcome_message", "Hello!");
const links = config.get<QuickLink[]>("quick_links", []);
```

The second argument to `get()` is the default value, returned when the setting has not been explicitly set.

> **Note:** `config.get()` in the UI context reads **airline-scoped** plugin configuration — settings managed by the VA admin on the Skyvex platform. User-scoped settings (personal preferences like unit system, display toggles, and refresh intervals) are managed through the shell's settings UI and are not accessible via this API.

## Navigation

Navigate within your plugin or jump to other plugins and shell routes:

```tsx theme={null}
const { navigation } = usePluginContext();

// Within your plugin (appends to /plugins/my-plugin/)
navigation.navigateTo("roster");
navigation.navigateTo("roster/pilot-123");

// To another plugin
navigation.navigateToPlugin("flight-tracking", "history");

// To a shell page
navigation.navigateToShell("/settings");

// Read the current path
const path = navigation.getCurrentPath();
```

For multi-page plugins, see the [Routing](/sdk/routing) page.

## Toast Notifications

```tsx theme={null}
const { toast } = usePluginContext();

toast.success("Flight booked successfully");
toast.error("Failed to connect to VA server");
toast.info("New PIREP available");
toast.warning("Low fuel warning");
```

Or use the dedicated hook:

```tsx theme={null}
import { useShellToast } from "@skyvexsoftware/stratos-sdk";

const { success, error, info, warning } = useShellToast();
```

## Styling

Plugins share the shell's Tailwind CSS theme. Use standard Tailwind utility classes:

```tsx theme={null}
<div className="bg-card rounded-lg border p-6">
  <h2 className="text-lg font-semibold">Section Title</h2>
  <p className="text-muted-foreground mt-2 text-sm">Supporting text</p>
</div>
```

Key design tokens available via Tailwind classes:

| Class                         | Usage                                  |
| ----------------------------- | -------------------------------------- |
| `bg-card`                     | Card and panel backgrounds             |
| `bg-muted`                    | Subtle, secondary backgrounds          |
| `text-muted-foreground`       | Secondary and supporting text          |
| `border`                      | Standard dividers and outlines         |
| `bg-primary` / `text-primary` | Accent colour (configured per-airline) |
| `bg-background`               | Page-level background                  |
| `text-foreground`             | Primary text                           |

The shell switches between light and dark Tailwind themes automatically — your components inherit the correct variables without any additional work.

## SDK UI Components

Import pre-built shadcn/ui components from the SDK to stay consistent with the shell's design:

```tsx theme={null}
import {
  Button,
  Card,
  CardHeader,
  CardTitle,
  CardContent,
  Badge,
  Input,
  Label,
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
  Tabs,
  TabsList,
  TabsTrigger,
  TabsContent,
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  Separator,
  Switch,
  Slider,
} from "@skyvexsoftware/stratos-sdk";
```

See [UI Components](/sdk/ui-components) for the full reference.

## Minimal Example

```tsx theme={null}
import { usePluginContext, Card, CardContent } from "@skyvexsoftware/stratos-sdk";

export default function MyPlugin() {
  const { auth, airline, toast } = usePluginContext();

  if (!auth.isAuthenticated || !auth.user) {
    return (
      <div className="flex h-full items-center justify-center">
        <p className="text-muted-foreground">Please log in to continue.</p>
      </div>
    );
  }

  return (
    <div className="p-6 space-y-4">
      <h1 className="text-2xl font-bold">
        Welcome, {auth.user.firstName}
      </h1>

      <Card>
        <CardContent className="p-4">
          <p className="text-muted-foreground text-sm">
            Connected to {airline?.name ?? "your VA"}
          </p>
        </CardContent>
      </Card>

      <button
        className="text-sm text-primary underline"
        onClick={() => toast.success("Hello from My Plugin!")}
      >
        Send toast
      </button>
    </div>
  );
}
```
