# BabylAI Help Center — Vue SDK

A Vue 3 component library for integrating BabylAI's help center widget into your Vue or Nuxt applications. The widget provides real-time chat support with AI assistance, human agent escalation, file attachments, in-chat reviews, and full RTL/Arabic support.

---

## Table of Contents

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
  - [initializeHelpCenter](#initializehelpcenter)
  - [getToken](#gettoken)
- [HelpCenter Component](#helpcenter-component)
  - [Props](#props)
  - [Examples](#examples)
- [Nuxt 3](#nuxt-3)
- [Theming](#theming)
- [RTL & Internationalization](#rtl--internationalization)
- [User Context](#user-context)
- [Local Development](#local-development)
- [Publishing](#publishing)
- [Architecture Overview](#architecture-overview)

---

## Installation

```bash
npm install @aslaluroba/help-center-vue
# or
yarn add @aslaluroba/help-center-vue
```

---

## Quick Start

**1. Initialize** once at app entry (before mounting):

```ts
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { initializeHelpCenter } from '@aslaluroba/help-center-vue'
import '@aslaluroba/help-center-vue/style.css'

initializeHelpCenter({
  baseUrl: 'https://your-api-url.com',
  getToken: async () => {
    const res = await fetch('/api/babylai-token')
    return res.json() // { accessToken: string, expiresAt: string }
  },
})

createApp(App).mount('#app')
```

**2. Drop the component** wherever you want the widget to appear (typically `App.vue`):

```vue
<script setup lang="ts">
import { HelpCenter } from '@aslaluroba/help-center-vue'
</script>

<template>
  <HelpCenter
    help-screen-id="your-help-screen-id"
    language="ar"
    primary-color="#ad49e1"
  />
</template>
```

The widget renders a fixed floating button — it doesn't affect your page layout.

---

## Configuration

### `initializeHelpCenter`

Call this **once** before mounting your Vue app. It configures the API base URL and the token provider.

```ts
import { initializeHelpCenter } from '@aslaluroba/help-center-vue'

initializeHelpCenter({
  baseUrl: 'https://your-api-url.com', // defaults to https://babylai.net/api
  getToken: myTokenFunction,
})
```

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `baseUrl` | `string` | No | Base URL for all API calls. Defaults to `https://babylai.net/api` |
| `getToken` | `() => Promise<TokenResponse>` | Yes | Async function that returns a valid bearer token |

### `getToken`

The `getToken` function must return a `TokenResponse` object:

```ts
type TokenResponse = {
  accessToken: string
  expiresAt: string // ISO 8601 date string
}
```

Typically this calls your backend, which in turn calls the BabylAI Auth API:

```ts
// src/chatBotToken.ts
const getToken = async (): Promise<TokenResponse> => {
  const response = await fetch(`${BASE_URL}/Auth/client/get-token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      tenantId: import.meta.env.VITE_TENANT_ID,
      apiKey:   import.meta.env.VITE_API_KEY,
    }),
  })
  if (!response.ok) throw new Error('Failed to fetch token')
  return response.json()
}

export default getToken
```

Then in `App.vue`:

```ts
import getToken from './chatBotToken'

initializeHelpCenter({
  baseUrl: import.meta.env.VITE_BASE_URL,
  getToken,
})
```

---

## HelpCenter Component

### Props

| Prop | Type | Default | Required | Description |
|------|------|---------|----------|-------------|
| `helpScreenId` | `string` | — | **Yes** | ID of the help screen configuration from the BabylAI dashboard |
| `language` | `'ar' \| 'en'` | `'ar'` | No | UI language. `'ar'` enables RTL layout automatically |
| `primaryColor` | `string` | — | No | Hex color for the widget accent (e.g. `'#ad49e1'`). Overrides the default purple theme |
| `showArrow` | `boolean` | `true` | No | Whether to show the floating message bubble above the help button on load |
| `messageLabel` | `string \| null` | `null` | No | Custom text for the floating message bubble. Falls back to the default translation |
| `user` | `UserData` | — | No | Authenticated user context passed to chat sessions |

#### `UserData`

```ts
type UserData = {
  id?: string
  name?: string
  email?: string
  avatar?: string
}
```

When provided, the user's identity is attached to new chat sessions, allowing agents to see who they are chatting with.

### Examples

**Minimal:**
```vue
<HelpCenter help-screen-id="abc123" />
```

**Full configuration:**
```vue
<HelpCenter
  help-screen-id="abc123"
  language="en"
  primary-color="#0ea5e9"
  :show-arrow="true"
  message-label="Need help? Chat with us!"
  :user="{ id: currentUser.id, name: currentUser.name, email: currentUser.email }"
/>
```

**Reactive user (updates when login state changes):**
```vue
<script setup lang="ts">
import { computed } from 'vue'
import { useAuth } from '@/composables/useAuth'
import { HelpCenter } from '@aslaluroba/help-center-vue'

const { user } = useAuth()
const helpUser = computed(() =>
  user.value ? { id: user.value.id, name: user.value.name, email: user.value.email } : undefined
)
</script>

<template>
  <HelpCenter
    help-screen-id="abc123"
    language="ar"
    :user="helpUser"
  />
</template>
```

---

## Nuxt 3

Create a plugin to initialize and register the component globally:

```ts
// plugins/help-center.client.ts
import { defineNuxtPlugin } from '#app'
import { initializeHelpCenter, HelpCenter } from '@aslaluroba/help-center-vue'
import '@aslaluroba/help-center-vue/style.css'

export default defineNuxtPlugin((nuxtApp) => {
  initializeHelpCenter({
    baseUrl: useRuntimeConfig().public.babylaiBaseUrl,
    getToken: async () => {
      const data = await $fetch('/api/babylai-token')
      return data
    },
  })

  nuxtApp.vueApp.component('HelpCenter', HelpCenter)
})
```

Then use it in any page or layout:

```vue
<template>
  <HelpCenter help-screen-id="abc123" language="ar" />
</template>
```

> **Note:** The `.client.ts` suffix ensures the plugin only runs in the browser (the widget uses WebSocket connections and browser APIs that are not available during SSR).

---

## Theming

Pass a hex color to `primary-color` and the SDK generates a full 11-stop color scale at runtime via CSS custom properties:

```vue
<HelpCenter primary-color="#ad49e1" ... />
```

This sets CSS variables on the widget's root element:

```css
--babylai-primary-color:     #ad49e1;
--babylai-primary-color-100: #f6ecfc; /* lightest */
--babylai-primary-color-500: #ad49e1; /* base */
--babylai-primary-color-950: #0a0310; /* darkest */
```

If `primary-color` is omitted, the default purple (`#ad49e1`) defined in `style.css` is used.

---

## RTL & Internationalization

Set `language="ar"` to automatically switch the widget to RTL layout using `tailwindcss-rtl` logical property utilities. No extra configuration is needed.

```vue
<!-- Arabic, RTL -->
<HelpCenter help-screen-id="abc123" language="ar" />

<!-- English, LTR -->
<HelpCenter help-screen-id="abc123" language="en" />
```

The widget is fully translated in both Arabic and English. All strings live in:
- `src/locales/ar.json`
- `src/locales/en.json`

---

## Local Development

Use Yarn’s `link` command to point a consumer app at this package’s folder (symlink). Run a watch build in the SDK so `dist/` stays up to date.

### Register the package (SDK repo, once)

```bash
cd babylai-fe-vue-sdk
yarn build   # ensure dist/ exists before linking
yarn link
```

### Watch mode (rebuild on every change)

```bash
# In babylai-fe-vue-sdk:
yarn dev
```

Each rebuild writes into `dist/`; the linked consumer resolves those files through the symlink.

### Link a consumer project

```bash
# In your consumer project (once):
yarn link @aslaluroba/help-center-vue
```

Restart the consumer dev server if Vite caches an old resolution after relinking.

### Unlink when done

```bash
# In the consumer:
yarn unlink @aslaluroba/help-center-vue
yarn install --force

# In the SDK (optional, clears global link registration):
yarn unlink
```

---

## Publishing

The SDK is published to NPM under the `@aslaluroba` scope.

```bash
# Patch release (1.0.0 → 1.0.1)
yarn publish:patch

# Minor release (1.0.0 → 1.1.0)
yarn publish:minor

# Major release (1.0.0 → 2.0.0)
yarn publish:major
```

Each command runs: `clean → build → version bump → npm publish --access public`.

> You must be logged in to npm (`npm login`) and have publish access to the `@aslaluroba` scope.

---

## Architecture Overview

```
src/
├── index.ts                        # Public entry — exports HelpCenter + initializeHelpCenter
├── services.ts                     # Secondary entry — exports raw API/Ably services
├── globals.css                     # Tailwind v4 + CSS custom properties (compiled into dist/style.css)
├── i18n.ts                         # i18next setup (ar + en locales)
│
├── core/                           # Framework-agnostic services (copied from React SDK)
│   ├── AblyService.ts              # WebSocket real-time connection (Ably)
│   ├── ApiService.ts               # HTTP client wrapper
│   ├── api.ts                      # API request helpers + presign upload/download
│   └── token-service.ts            # Token caching + refresh logic
│
├── lib/
│   ├── config.ts                   # Singleton ConfigService (stores baseUrl + getToken)
│   ├── types.ts                    # All public TypeScript interfaces
│   ├── utils.ts                    # cn() class merge helper
│   ├── theme-utils.ts              # Primary color → CSS variable generator
│   └── composables/
│       ├── useLanguage.ts          # inject('babylai-language') → 'ar' | 'en'
│       ├── useLocalTranslation.ts  # t(), dir (rtl/ltr), i18n instance
│       ├── useTypewriter.ts        # Animated character-by-character text reveal
│       └── useActionHandler.ts     # Ably action dispatch (needs_agent, end_session)
│
├── components/
│   ├── shared/Button.vue           # CVA-powered button with variant support
│   └── ui/
│       ├── AgentResponse.vue       # Markdown renderer with typewriter animation
│       ├── ImageAttachment.vue     # Lazy image loader (presign download for IDs)
│       └── ImagePreviewDialog.vue  # Full-screen image gallery with zoom/pan
│
└── ui/
    ├── HelpCenter.vue              # Root — provides language, owns all state + API calls
    ├── HelpButton.vue              # Fixed floating action button
    ├── FloatingMessage.vue         # Bubble above the help button
    ├── HelpPopup.vue               # Screen state machine (options ↔ chat ↔ review)
    ├── PoweredBy.vue               # Branding footer
    ├── chatbot-popup/
    │   ├── ActiveChatActions.vue   # Overlay when a session exists but popup is collapsed
    │   ├── chat-window-screen/
    │   │   ├── ChatWindow.vue      # Message list + scroll + gallery
    │   │   ├── ChatWindowHeader.vue
    │   │   ├── ChatWindowFooter.vue  # Text input + image upload (presign → S3 PUT)
    │   │   ├── InChatReview.vue    # Rating + comment form shown inline after session
    │   │   └── TypingIndicator.vue
    │   ├── options-list-screen/
    │   │   └── OptionsListScreen.vue + subcomponents
    │   ├── loading-screen/LoadingScreen.vue
    │   └── error-screen/ErrorScreen.vue
    ├── confirmation-modal/ConfirmationModal.vue
    └── review-dialog/
        ├── ReviewDialog.vue        # Standalone review modal (shown after ending chat)
        └── Rating.vue              # 1–5 star selector
```

### Data flow

```
initializeHelpCenter()          → configures ConfigService (baseUrl, getToken)
HelpCenter.vue (root)
  ├─ provides 'babylai-language' → consumed by useLanguage() in all children
  ├─ loads HelpScreenData        → GET /client/clientHelpScreen/:id
  ├─ handleStartChat()           → POST /Client/ClientChatSession/create-session
  │    └─ ClientAblyService.startConnection() → WebSocket to Ably
  ├─ handleSendMessage()         → POST /Client/ClientChatSession/:id/send-message
  ├─ handleEndChat()             → POST /Client/ClientChatSession/:id/close
  └─ handleSendChatReview()      → POST /Client/ClientChatSession/:id/review
```

### Realtime events (Ably)

| Action type | Trigger | Effect |
|-------------|---------|--------|
| `needs_agent` | Admin assigns a human agent | Sets `needsAgent = true`, shows agent avatar in chat |
| `end_session` | Admin closes session from dashboard | Ends chat locally without calling the close API |
| message received | Bot or agent sends a message | Appends to `messages[]`, triggers typewriter animation |
