<!-- # Cdial Agent PRO Widget SDK -->
# Indigenius AI Widget

`CdialWidget` is a powerful SDK for integrating AI Agent call widget into your web application, offering functionalities to easily initiate and manage calls with your AI-powered customer service agents.

## ✨ Features

- 🎯 **Full TypeScript Support** - Complete type definitions included
- 📦 **Multiple Installation Methods** - npm, CDN, or direct URL
- ⚛️ **Framework Agnostic** - Works with React, Vue, Angular, Next.js, and more
- 🌐 **Browser Compatible** - Works in all modern browsers
- 🔧 **Zero Configuration** - Auto-detects TypeScript and provides IntelliSense
- 🎨 **Customizable UI** - Use built-in UI or build your own

## Installation

To use the SDK in your project, you can either:

### 1. **Install via npm** (Recommended - Full TypeScript Support)

   ```bash
   npm install indigenius-ai-widget
   ```

   TypeScript types are automatically included! No need for `@types/` packages or manual declarations.

### 2. **Include the UMD build via CDN** (For HTML/JavaScript projects)

   ```html
   <script src="https://cdn.jsdelivr.net/npm/indigenius-ai-widget@latest/dist/sdk.umd.js"></script>
   ```

   **For TypeScript types with CDN usage**, add this to your `tsconfig.json`:

   ```json
   {
     "compilerOptions": {
       "types": ["node_modules/indigenius-ai-widget/dist/index.d.ts"]
     }
   }
   ```

   Or install types separately:

   ```bash
   npm install --save-dev indigenius-ai-widget
   ```

### 3. **Include the official URL** (Direct integration)

   ```html
   <script type="module" src="https://widget.indigenius.ai/v1/index.js"></script>
   ```

---

## 🚀 TypeScript Usage

The SDK is fully TypeScript compatible with complete type definitions included. No additional setup required!

### **Next.js Example** (App Router)

```typescript
// app/components/CdialWidget.tsx
'use client';

import { useEffect, useRef, useState } from 'react';
import { Cdial } from 'indigenius-ai-widget';

export default function CdialWidgetComponent() {
  const widgetRef = useRef<Cdial.CdialWidget | null>(null);
  const [callState, setCallState] = useState<'idle' | 'dialing' | 'connected' | 'ended'>('idle');
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    // Dynamic import to avoid SSR issues
    import('indigenius-ai-widget').then(({ CdialWidget }) => {
      const widget = new CdialWidget({
        agentId: 'your-agent-id',
        mountUI: false, // Control from your own UI
      });

      widgetRef.current = widget;

      // Type-safe event listeners
      widget.on('dialing', () => setCallState('dialing'));
      widget.on('connected', () => setCallState('connected'));
      widget.on('ended', () => setCallState('ended'));
      widget.on('error', (error) => console.error('Widget error:', error));

      widget.init();
      setIsReady(true);
    });

    return () => widgetRef.current?.destroy();
  }, []);

  const toggleCall = () => {
    widgetRef.current?.toggleCall();
  };

  return (
    <div>
      <h1>AI Agent Widget</h1>
      <button 
        onClick={toggleCall} 
        disabled={!isReady}
        className="px-4 py-2 bg-blue-500 text-white rounded"
      >
        {callState === 'connected' ? '🔴 End Call' : 
         callState === 'dialing' ? '⏳ Dialing...' : 
         '📞 Start Call'}
      </button>
      {!isReady && <p>Loading widget...</p>}
    </div>
  );
}
```

### **TypeScript with Vite/React**

```typescript
// src/components/Widget.tsx
import { useEffect, useRef, useState } from 'react';
import { Cdial, CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';

function Widget() {
  const widgetRef = useRef<Cdial.CdialWidget | null>(null);
  const [callState, setCallState] = useState<'idle' | 'dialing' | 'connected' | 'ended'>('idle');

  useEffect(() => {
    // Type-safe options
    const options: CdialWidgetOptions = {
      agentId: process.env.VITE_AGENT_ID || 'your-agent-id',
      mountUI: true,
    };

    const widget = new CdialWidget(options);
    widgetRef.current = widget;

    // Fully typed event handlers
    widget.on('dialing', () => setCallState('dialing'));
    widget.on('connected', () => setCallState('connected'));
    widget.on('ended', () => setCallState('ended'));
    widget.on('error', (err) => {
      console.error('Error:', err);
    });

    widget.init();

    return () => widget.destroy();
  }, []);

  return (
    <div>
      <h1>Status: {callState}</h1>
    </div>
  );
}

export default Widget;
```

### **Vue 3 + TypeScript**

```vue
<!-- components/CdialWidget.vue -->
<template>
  <div>
    <h1>AI Agent Widget - {{ callState }}</h1>
    <button @click="toggleCall" :disabled="!isReady">
      {{ buttonLabel }}
    </button>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
import { Cdial, CdialWidget } from 'indigenius-ai-widget';

type CallState = 'idle' | 'dialing' | 'connected' | 'ended';

const callState = ref<CallState>('idle');
const isReady = ref(false);
let widget: Cdial.CdialWidget | null = null;

onMounted(() => {
  widget = new CdialWidget({
    agentId: 'your-agent-id',
    mountUI: false,
  });

  widget.on('dialing', () => (callState.value = 'dialing'));
  widget.on('connected', () => (callState.value = 'connected'));
  widget.on('ended', () => (callState.value = 'ended'));
  widget.on('error', (err) => console.error(err));

  widget.init();
  isReady.value = true;
});

onBeforeUnmount(() => {
  widget?.destroy();
});

const toggleCall = () => widget?.toggleCall();

const buttonLabel = computed(() =>
  callState.value === 'connected' ? 'End Call' : 'Start Call'
);
</script>
```

### **Angular with TypeScript**

```typescript
// app/components/widget/widget.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Cdial, CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';

@Component({
  selector: 'app-cdial-widget',
  template: `
    <div>
      <h1>AI Agent Widget - {{ callState }}</h1>
      <button (click)="toggleCall()" [disabled]="!isReady">
        {{ buttonLabel }}
      </button>
    </div>
  `,
  styles: [`
    button {
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
    }
    button:disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  `]
})
export class WidgetComponent implements OnInit, OnDestroy {
  callState: 'idle' | 'dialing' | 'connected' | 'ended' = 'idle';
  isReady = false;
  private widget: Cdial.CdialWidget | null = null;

  get buttonLabel(): string {
    switch (this.callState) {
      case 'connected': return '🔴 End Call';
      case 'dialing': return '⏳ Dialing...';
      default: return '📞 Start Call';
    }
  }

  ngOnInit(): void {
    const options: CdialWidgetOptions = {
      agentId: 'your-agent-id',
      mountUI: false,
    };

    this.widget = new CdialWidget(options);

    this.widget.on('dialing', () => {
      this.callState = 'dialing';
    });

    this.widget.on('connected', () => {
      this.callState = 'connected';
    });

    this.widget.on('ended', () => {
      this.callState = 'ended';
    });

    this.widget.on('error', (err) => {
      console.error('Widget error:', err);
    });

    this.widget.init();
    this.isReady = true;
  }

  ngOnDestroy(): void {
    this.widget?.destroy();
  }

  toggleCall(): void {
    this.widget?.toggleCall();
  }
}
```

### **Vanilla TypeScript**

```typescript
// src/app.ts
import { Cdial, CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';

class App {
  private widget: Cdial.CdialWidget;

  constructor() {
    const options: CdialWidgetOptions = {
      agentId: 'your-agent-id',
      mountUI: true,
    };

    this.widget = new CdialWidget(options);
    this.setupEventListeners();
    this.widget.init();
  }

  private setupEventListeners(): void {
    this.widget.on('dialing', () => {
      console.log('Call is dialing...');
      this.updateUI('dialing');
    });

    this.widget.on('connected', () => {
      console.log('Call connected!');
      this.updateUI('connected');
    });

    this.widget.on('ended', () => {
      console.log('Call ended');
      this.updateUI('ended');
    });

    this.widget.on('error', (error) => {
      console.error('Call error:', error);
      alert(`Error: ${error}`);
    });
  }

  private updateUI(state: string): void {
    const statusEl = document.getElementById('status');
    if (statusEl) {
      statusEl.textContent = `Status: ${state}`;
    }
  }

  public cleanup(): void {
    this.widget.destroy();
  }
}

// Initialize the app
const app = new App();

// Cleanup on page unload
window.addEventListener('beforeunload', () => {
  app.cleanup();
});
```

### **TypeScript Type Definitions**

The package exports the following types:

```typescript
// Namespace export
import { Cdial } from 'indigenius-ai-widget';

// Named exports
import { CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';

// Types
type CallState = 'idle' | 'dialing' | 'connected' | 'ended';
type EventType = 'dialing' | 'connected' | 'ended' | 'error';
type EventCallback = (data?: any) => void;

// Options interface
interface CdialWidgetOptions {
  agentId: string;
  mountUI?: boolean; // default: false
}

// Widget class methods
class CdialWidget {
  constructor(options: CdialWidgetOptions);
  init(): void;
  startCall(theme?: any): Promise<void>;
  endCall(): void;
  toggleCall(): void;
  isCalling(): boolean;
  destroy(): void;
  on(event: EventType, callback: EventCallback): void;
}
```

---

## 🌐 CDN Usage with TypeScript

For projects using the CDN version but still want TypeScript support:

### Option 1: Install Types Only

```bash
npm install --save-dev indigenius-ai-widget
```

Then in your HTML:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Widget with CDN + TypeScript</title>
</head>
<body>
  <indigenius-convai agent-id="your-agent-id"></indigenius-convai>
  
  <!-- CDN Script -->
  <script src="https://cdn.jsdelivr.net/npm/indigenius-ai-widget@latest/dist/sdk.umd.js"></script>
  
  <script>
    // TypeScript will recognize Cdial and CdialWidget types
    window.addEventListener('load', () => {
      const widget = window.widget; // Fully typed!
      
      widget.on('connected', () => {
        console.log('Connected');
      });
    });
  </script>
</body>
</html>
```

### Option 2: Type Reference from CDN

Types are available at these URLs:
- **jsDelivr**: `https://cdn.jsdelivr.net/npm/indigenius-ai-widget@latest/dist/index.d.ts`
- **unpkg**: `https://unpkg.com/indigenius-ai-widget@latest/dist/index.d.ts`

You can reference them in your TypeScript project or create a local type declaration.

### Option 3: Manual Type Declaration

Create a `indigenius-ai-widget.d.ts` file in your project:

```typescript
declare module 'indigenius-ai-widget' {
  export namespace Cdial {
    interface CdialWidgetOptions {
      agentId: string;
      mountUI?: boolean;
    }
    
    class CdialWidget {
      constructor(options: CdialWidgetOptions);
      init(): void;
      toggleCall(): void;
      startCall(theme?: any): Promise<void>;
      endCall(): void;
      isCalling(): boolean;
      destroy(): void;
      on(event: 'dialing' | 'connected' | 'ended' | 'error', callback: (data?: any) => void): void;
    }
  }
  
  export const CdialWidget: typeof Cdial.CdialWidget;
  export type CdialWidgetOptions = Cdial.CdialWidgetOptions;
}

declare global {
  interface Window {
    Cdial: typeof import('indigenius-ai-widget').Cdial;
    CdialWidget: typeof import('indigenius-ai-widget').CdialWidget;
    widget?: InstanceType<typeof import('indigenius-ai-widget').CdialWidget>;
  }
}

export {};
```

---

### HTML Integration

You can integrate the widget into your HTML file with the following steps:

1. Add the `<indigenius-convai>` component to your HTML body to display the widget.
2. Include the SDK script (either from a CDN or local build).

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Webapp</title>
  </head>
  <body>
    <h1>Welcome to my random HTML site...</h1>

    <!-- Add the widget component -->
    <indigenius-convai agent-id="your-agent-id"></indigenius-convai>

    <!-- Add the SDK script (local or CDN) -->
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/indigenius-ai-widget@1.0.0/dist/sdk.umd.js"
    ></script>

    <script defer>
      // Initialize event listeners
      window.addEventListener("load", () => {
        widget.on("dialing", () => {
          console.log("Dialing detected");
        });
        widget.on("connected", () => {
          console.log("Connected detected");
        });
        widget.on("ended", () => {
          console.log("Ended detected");
        });
        widget.on("error", (err) => {
          console.error("Error:", err);
        });
      });
    </script>
  </body>
</html>
```


## Framework Usage

### Widget Options (`CdialWidget` Constructor Payload)

When creating a new `CdialWidget` instance, you pass an options object. Here are the available options:

| Option     | Type      | Required | Default | Description                                                                 |
|------------|-----------|----------|---------|-----------------------------------------------------------------------------|
| `agentId`  | `string`  | Yes      | —       | The unique Agent ID for your AI agent.                                      |
| `mountUI`  | `boolean` | No       | `false` | If `true`, the widget's floating UI is auto-mounted. If `false`, no UI is rendered and you control everything via the API. |

**Example:**

```js
const widget = new CdialWidget({
  agentId: 'your-agent-id',
  mountUI: true, // Set to false to use your own UI
});
```


### Initialize the Widget

The `init` method is used to initialize the widget with your options. You must provide a valid `agentId`. If you set `mountUI: true`, the widget's floating UI will appear automatically. If `mountUI: false`, you can build your own UI and control the widget programmatically.

```js
import { CdialWidget } from "indigenius-ai-widget";

const widget = new CdialWidget({
  agentId: "your-agent-id",
  mountUI: true, // or false for custom UI
});

widget.init().then(() => {
  console.log("Widget initialized");
});
```

### Toggle Call

Use `toggleCall` to start or end a call. This method toggles the widget between the "call in progress" state and the "idle" state.

```js
widget.toggleCall(); // Starts or ends the call based on the current state
```

You can listen to events related to call state changes.

### Event Listeners

The SDK supports various events that you can listen to for user interaction or state changes.

#### Example: Listening to Call Start and End Events


```
// Listen to call started
widget.on("callStarted", () => {
  console.log("Call has started");
});

// Listen to call ended
widget.on("callEnded", () => {
  console.log("Call has ended");
});
```

### Destroy the Widget

To clean up and remove the widget from the page, use the `destroy` method. This is useful if you need to remove the widget entirely after use.

```js
widget.destroy();
```

This method will remove all elements created by the widget and stop any ongoing call operations.

---

## Full Example

Here’s a complete example of how to use the widget:

---


## Modern Framework Integration

You can use the widget in React, Vue, or Angular. The `mountUI` option gives you full control over whether the floating widget UI appears, or if you want to build your own UI and use the widget's API.

---


### React Example ([Live Demo](https://stackblitz.com/edit/indigenius-ai-widget-react-demo))

```jsx
import './App.css';
import { useEffect, useRef, useState } from 'react';
import { CdialWidget } from 'indigenius-ai-widget';

function App() {
  const widgetRef = useRef(null);
  const [callState, setCallState] = useState('idle');
  const [widgetReady, setWidgetReady] = useState(false);

  useEffect(() => {
    // Use mountUI: false to control the call from your React button only
    const widget = new CdialWidget({
      agentId: 'your-agent-id',
      mountUI: false, // Only your React button will control the call
    });
    widgetRef.current = widget;

    widget.on('dialing', () => setCallState('dialing'));
    widget.on('connected', () => setCallState('connected'));
    widget.on('ended', () => setCallState('ended'));
    widget.on('error', console.error);

    widget.init().then(() => setWidgetReady(true));

    return () => widget.destroy();
  }, []);

  const toggleCall = () => widgetRef.current?.toggleCall();

  return (
    <div>
      <h1>Cdial Widget Demo</h1>
      <button onClick={toggleCall} disabled={!widgetReady}>
        {callState === 'connected'
          ? 'End Call'
          : callState === 'dialing'
          ? 'Dialing...'
          : 'Start Call'}
      </button>
      {!widgetReady && <p>Loading widget...</p>}
    </div>
  );
}

export default App;
```

---


### Vue Example

```vue
<template>
  <div>
    <h1>Cdial Widget Demo (Vue)</h1>
    <button @click="toggleCall">{{ buttonLabel }}</button>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
import { CdialWidget } from 'indigenius-ai-widget';

const callState = ref('idle');
let widget = null;

onMounted(() => {
  widget = new CdialWidget({
    agentId: 'your-agent-id',
    mountUI: true, // Set to false to use your own UI
  });

  widget.on('dialing', () => callState.value = 'dialing');
  widget.on('connected', () => callState.value = 'connected');
  widget.on('ended', () => callState.value = 'ended');
  widget.on('error', console.error);

  widget.init();
});

onBeforeUnmount(() => {
  widget?.destroy();
});

const toggleCall = () => widget?.toggleCall();

const buttonLabel = computed(() =>
  callState.value === 'connected' ? 'End Call' : 'Start Call'
);
</script>
```

---


### Angular Example

```typescript
// app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CdialWidget } from 'indigenius-ai-widget';

@Component({
  selector: 'app-root',
  template: `
    <h1>Cdial Widget Demo (Angular)</h1>
    <button (click)="toggleCall()">{{ buttonLabel }}</button>
  `
})
export class AppComponent implements OnInit, OnDestroy {
  callState = 'idle';
  widget: any;

  get buttonLabel() {
    return this.callState === 'connected' ? 'End Call' : 'Start Call';
  }

  ngOnInit() {
    this.widget = new CdialWidget({
      agentId: 'your-agent-id',
      mountUI: true, // Set to false to use your own UI
    });

    this.widget.on('dialing', () => this.callState = 'dialing');
    this.widget.on('connected', () => this.callState = 'connected');
    this.widget.on('ended', () => this.callState = 'ended');
    this.widget.on('error', console.error);

    this.widget.init();
  }

  ngOnDestroy() {
    this.widget?.destroy();
  }

  toggleCall() {
    this.widget?.toggleCall();
  }
}
```

---

### Summary

- **mountUI: true** — Widget’s floating UI is auto-mounted (recommended for most use cases).
- **mountUI: false** — No UI is rendered; you control everything via the widget API (advanced/custom UI).
- The widget is fully self-contained and will not create duplicate UIs, even if instantiated multiple times in a framework.
- All public methods (`init`, `destroy`, `toggleCall`, `on`, etc.) are available on the widget instance.

---

## Methods

### `init()`

Initializes the widget with the given `agentId` and sets up the UI.

**Returns**: `Promise<void>`

### `toggleCall()`

Starts or ends a call based on the current widget state.

**Returns**: `void`

### `destroy()`

Destroys the widget, removing all associated elements and cleaning up resources.

**Returns**: `void`

---

## Events

The widget emits several events that you can listen to for customizing your application's behavior. Below is a list of available events, their descriptions, and usage examples.

### 📡 `dialing`

Emitted when the widget starts attempting to connect to the AI agent.

**Example:**

```js
myCdialWidget.on("dialing", () => {
  console.log("Dialing detected");
});
```

---

### 🔗 `connected`

Emitted when the connection to the AI agent is successfully established.

**Example:**

```js
myCdialWidget.on("connected", () => {
  console.log("Connected detected");
});
```

---

### ❌ `ended`

Emitted when the call has ended or was terminated.

**Example:**

```js
myCdialWidget.on("ended", () => {
  console.log("Ended detected");
});
```

---



### ⚠️ `error`

Emitted if there is an internal error during the operation of the widget.

**Payload:** `err` (Error or string) – details about the error that occurred.

**Example:**

```js
myCdialWidget.on("error", (err) => {
  console.error("Error:", err);
});
```

---

You can register these event listeners after the widget has loaded:

```html
<script defer>
  window.addEventListener("load", () => {
    myCdialWidget.on("dialing", () => {
      console.log("Dialing detected");
    });

    myCdialWidget.on("connected", () => {
      console.log("Connected detected");
    });

    myCdialWidget.on("ended", () => {
      console.log("Ended detected");
    });

    myCdialWidget.on("error", (err) => {
      console.error("Error:", err);
    });
  });
</script>
```

---

## 🔧 TypeScript Verification

### Verify Types are Working

After installing the package, verify TypeScript support:

```typescript
// test.ts
import { Cdial, CdialWidget } from 'indigenius-ai-widget';

// Should show IntelliSense for options
const widget = new CdialWidget({
  agentId: 'test', // ✅ Required
  mountUI: true,   // ✅ Optional with autocomplete
});

// Should show method autocomplete
widget.init();
widget.toggleCall();
widget.on('connected', () => {}); // ✅ Event names autocompleted
widget.destroy();
```

Run TypeScript compiler:
```bash
npx tsc test.ts --noEmit
```

If no errors appear, TypeScript is configured correctly! ✅

### Troubleshooting TypeScript

**Problem**: Types not detected

**Solutions**:
1. Ensure package is installed: `npm install indigenius-ai-widget`
2. Restart your IDE/TypeScript server
3. Check `tsconfig.json` has `moduleResolution: "node"`
4. Run `npm install` again to refresh types

**Problem**: CDN usage without types

**Solution**:
```bash
# Install types as dev dependency
npm install --save-dev indigenius-ai-widget
```

### IDE Support

The package works with:
- ✅ VS Code (IntelliSense + autocomplete)
- ✅ WebStorm/IntelliJ IDEA
- ✅ Sublime Text (with LSP)
- ✅ Vim/Neovim (with CoC or LSP)

---

## 📚 Additional Resources

- 📘 [Complete TypeScript Guide](./TYPESCRIPT.md)
- 💡 [TypeScript Usage Examples](./examples/typescript-usage.ts)
- ⚛️ [Next.js Example](./examples/nextjs-typescript.tsx)
- 🌐 [HTML Integration Example](./examples/namespace-usage.html)
- 📦 [npm Package](https://www.npmjs.com/package/indigenius-ai-widget)
- 🐙 [GitHub Repository](https://github.com/CDIAL-Org/cdial-agent-widget-sdk)

---

This SDK is released under the MIT License. See LICENSE for more details.

---
