# 🚀 Quala Widget v1.2.0

Turn "it's broken" into actionable debugging intelligence with contextual feedback widgets.

## ✨ What's New in v1.2.0

- **🎯 Conditional Micro Widgets**: Micro widgets only load when enabled for your project
- **🧠 Contextual Intelligence**: Questions and feedback options adapt to trigger type
- **🛡️ Advanced Anti-Spam**: Intelligent widget frequency management
- **📱 Enhanced Offline Support**: Queue feedback when offline, sync when online
- **🔧 Technical Context Capture**: Automatic collection of errors, device info, and user actions
- **⚡ Performance Optimized**: Minimal overhead when features aren't enabled
- **🎨 Trigger-Specific Styling**: Different emoji sets per trigger type

## 📦 Installation

### NPM
```bash
npm install quala-widget
```

### CDN
```html
<script src="https://unpkg.com/quala-widget@1.2.0/dist/quala.umd.js"></script>
```

## 🚀 Quick Start

### 1. Initialize the SDK
```javascript
import { qualaSdk } from 'quala-widget';

// Initialize with your API key
await qualaSdk.initialize('your-api-key', {
  debug: true, // Enable for development
  apiBaseUrl: 'https://www.getquala.xyz/api/widget' // Optional custom URL
});
```

### 2. Identify Users
```javascript
// Identify the user to enable feedback
await qualaSdk.identifyUser({
  userId: 'user-123',
  email: 'user@company.com',
  trialStartDate: '2025-01-01' // Optional
});
```

### 3. Ready! 🎉
That's it! The SDK will automatically:
- ✅ Show regular feedback widgets if configured
- ✅ Enable micro widgets if configured for your project
- ✅ Set up intelligent triggers based on user behavior
- ✅ Capture technical context when issues occur

## 🎣 React Hooks

For React applications, use the provided hooks for cleaner integration:

### useQualaInit Hook
Initialize Quala in your app component with automatic cleanup:

```tsx
import { useQualaInit } from 'quala-widget';

function App() {
  useQualaInit({
    apiKey: 'your-api-key',
    options: {
      debug: true,
      apiBaseUrl: 'https://www.getquala.xyz/api/widget' // Optional
    }
  });

  return <div>Your App</div>;
}
```

### useQuala Hook
Access Quala functionality in any component:

```tsx
import { useQuala } from 'quala-widget';

function UserProfile({ userId, email }) {
  const { identifyUser, trackEvent, triggerSmartFeedback } = useQuala();

  useEffect(() => {
    // Identify user when component mounts
    identifyUser({
      userId,
      email,
      trialStartDate: '2025-01-01'
    });
  }, [userId, email]);

  const handleFeatureUsed = () => {
    trackEvent('feature_used', {
      feature: 'user-profile',
      section: 'settings'
    });
  };

  const handleFeedbackRequest = async () => {
    await triggerSmartFeedback();
  };

  return (
    <div>
      <button onClick={handleFeatureUsed}>Use Feature</button>
      <button onClick={handleFeedbackRequest}>Give Feedback</button>
    </div>
  );
}
```

### TypeScript Support
Full TypeScript support with proper typing:

```tsx
import { useQuala, type QualaUser } from 'quala-widget';

const user: QualaUser = {
  userId: 'user-123',
  email: 'user@company.com',
  trialStartDate: '2025-01-01'
};

const { identifyUser } = useQuala();
identifyUser(user); // ✅ Fully typed
```

### Hook Benefits
- **Automatic Cleanup**: `useQualaInit` handles SDK destruction on unmount
- **React-Friendly**: No need to manage SDK lifecycle manually  
- **TypeScript Ready**: Full type safety out of the box
- **Lightweight**: Hooks only wrap the core SDK, no extra overhead

## 🎯 Micro Widgets (Conditional Feature)

Micro widgets are **conditionally loaded** based on your project configuration. They only activate when:
1. Your project has micro widgets enabled in the dashboard
2. Valid trigger configuration exists
3. Anti-spam conditions are met

### Smart Triggers

When enabled, micro widgets respond to 5 intelligent triggers:

| Trigger | When It Shows | Default Question | Emoji Set |
|---------|---------------|------------------|-----------|
| **🕒 Time** | After user spends time on page | "How has your experience been so far?" | Detailed (😍😊😐😕😤) |
| **🚪 Exit Intent** | When user moves to leave | "Before you go, how can we improve?" | Exit-focused (👍🤷😕) |
| **⚡ Console Error** | When JavaScript errors occur | "We noticed some technical issues. How can we help?" | Technical (✅🤔🐞) |
| **📝 Form Failure** | When form submissions fail | "Having trouble with the form?" | Technical (✅🤔🐞) |
| **🔧 API Failure** | When API calls fail | "Something went wrong. What can we fix?" | Technical (✅🤔🐞) |

### Contextual Intelligence

Each trigger type gets **contextual questions and appropriate feedback options**:

```javascript
// Example: Console error detected
// Question: "We noticed some technical issues. How can we help?"
// Options: ✅ Working fine  🤔 Something's off  🐞 It's broken

// Example: Exit intent detected  
// Question: "Before you go, how can we improve?"
// Options: 👍 All good  🤷 Just browsing  😕 Something's wrong
```

## 📊 Technical Context Capture

When micro widgets are enabled, the SDK automatically captures:

```javascript
{
  device: {
    userAgent: "Chrome/91.0...",
    viewport: "1920x1080",
    timezone: "America/New_York"
  },
  performance: {
    loadTime: 1250,
    memoryUsage: "45MB",
    connectionType: "4g"
  },
  errors: [
    {
      message: "Cannot read property 'x' of undefined",
      stack: "...",
      timestamp: "2025-01-15T10:30:00Z"
    }
  ],
  networkFailures: [
    {
      url: "/api/users",
      status: 500,
      timestamp: "2025-01-15T10:29:55Z"
    }
  ],
  userActions: [
    { type: "click", element: "button#submit", timestamp: "..." },
    { type: "form_submit", form: "login-form", timestamp: "..." }
  ]
}
```

## 🛡️ Anti-Spam System

Intelligent frequency management prevents widget fatigue:

- **Global Cooldown**: Minimum 45 seconds between any widgets
- **Trigger Priorities**: Critical errors override time-based triggers
- **Session Limits**: Maximum 3 widgets per session
- **Individual Cooldowns**: Each trigger type has its own cooldown
- **Smart Override**: High-priority triggers can override cooldowns

```javascript
// Check anti-spam status (debug mode only)
const status = qualaSdk.getAntiSpamStatus();
console.log(status);
// {
//   enabled: true,
//   globalCooldownRemaining: 15000,
//   sessionWidgetCount: 1,
//   lastWidgetType: 'time',
//   canShow: true
// }
```

## 🎮 Runtime Configuration

### Configure Micro Widgets
```javascript
qualaSdk.configureMicroWidget({
  position: 'bottom-left',
  question: 'Custom question for all triggers',
  emojiSet: 'simple', // 'default' | 'simple' | 'detailed'
  autoHide: true,
  hideDelay: 8000
});
```

### Check Availability
```javascript
// Check if regular feedback trigger is available
const available = await qualaSdk.checkTriggerAvailable();

// Refresh trigger status
const refreshed = await qualaSdk.refreshTriggerStatus();
```

## 📱 Regular Feedback Widgets

Traditional feedback forms still work as before:

```javascript
// These will show automatically when triggers are configured
// Or manually trigger:
await qualaSdk.triggerSmartFeedback();
```

## 🔧 Advanced Configuration

### Event Listeners
```javascript
// Listen to SDK events
qualaSdk.on('micro_widget_shown', ({ triggerType, config }) => {
  console.log(`Micro widget shown for ${triggerType}`);
});

qualaSdk.on('micro_feedback_submitted', ({ feedback, triggerType, technicalContext }) => {
  console.log('Feedback submitted:', feedback);
});

qualaSdk.on('user_identified', ({ user, session }) => {
  console.log('User identified:', user.userId);
});

qualaSdk.on('config_updated', ({ config, reason }) => {
  console.log('Config updated:', reason);
});

// Remove listeners
qualaSdk.off('micro_widget_shown');
```

### Debug Mode
```javascript
await qualaSdk.initialize('your-api-key', { 
  debug: true 
});

// Debug-only methods
qualaSdk.forceAllowNextWidget(); // Bypass anti-spam
qualaSdk.resetAntiSpamState(); // Reset anti-spam counters
await qualaSdk.forceConfigRefresh(); // Force config update
```

### Get Session Info
```javascript
const info = qualaSdk.getSessionInfo();
console.log(info);
// {
//   sessionToken: "abc123...",
//   questionGroupId: "uuid...",
//   isInitialized: true,
//   microWidgetEnabled: true,
//   antiSpam: { ... } // Debug mode only
// }
```

### Get Technical Context
```javascript
// Only available when micro widgets are enabled
const context = qualaSdk.getTechnicalContext();
if (context) {
  console.log('Current technical state:', context);
}
```

## 📊 Analytics & Tracking

The SDK automatically tracks key events:

```javascript
// Manual event tracking
qualaSdk.trackEvent('feature_used', {
  feature: 'advanced-search',
  userId: 'user-123'
});

qualaSdk.trackEvent('milestone_reached', {
  milestone: 'onboarding_complete',
  timeToComplete: 120000
});
```

**Automatic Events:**
- `user_identified` - When user is identified
- `micro_widget_shown` - When micro widget appears  
- `micro_feedback_submitted` - When micro feedback is submitted
- `feedback_widget_triggered` - When regular widget triggers
- `anti_spam_blocked` - When anti-spam prevents display
- `config_updated` - When configuration changes

## 🌐 Offline Support

The SDK gracefully handles offline scenarios:

- **Offline Queue**: Feedback is queued when offline
- **Auto-Sync**: Syncs when connection returns
- **Persistence**: Uses localStorage as backup
- **Retry Logic**: Automatic retry with exponential backoff

```javascript
// Feedback submitted offline will be automatically synced
// when the user comes back online
```

## 🎯 Conditional Loading

Key features are **conditionally loaded** based on configuration:

| Feature | Loads When |
|---------|------------|
| **Micro Widgets** | Project has micro widgets enabled |
| **Technical Context** | Micro widgets are enabled |
| **Anti-Spam Manager** | Micro widgets are enabled |
| **Trigger Listeners** | Micro widgets enabled + triggers configured |
| **Config Refresh** | Micro widgets are enabled |

This ensures **minimal overhead** when features aren't needed.

## 🚫 Error Handling

```javascript
try {
  await qualaSdk.initialize('invalid-key');
} catch (error) {
  console.error('SDK initialization failed:', error);
}

// Listen for errors
qualaSdk.on('sdk_error', ({ error, phase }) => {
  console.error(`SDK error in ${phase}:`, error);
});

qualaSdk.on('widget_load_error', ({ error }) => {
  console.error('Widget failed to load:', error);
});
```

## 🔐 Security & Privacy

- **Domain Filtering**: Sensitive domains (auth, payment) are excluded from context
- **Data Minimization**: Only necessary technical data is collected
- **Local Storage**: Minimal use of localStorage for offline support
- **Session-Based**: All data tied to user sessions

## 🗂️ Project Configuration

Configure your project's feedback strategy through the Quala dashboard:

- **Trigger Selection**: Choose which behavioral triggers to enable
- **Contextual Questions**: Customize questions per trigger type
- **Emoji Sets**: Select appropriate feedback styles for each context
- **Technical Context**: Enable detailed error and performance capture
- **Anti-Spam Settings**: Configure frequency and priority rules

## 🧪 Testing

```javascript
// Test in development
await qualaSdk.initialize('your-api-key', {
  debug: true,
  apiBaseUrl: 'http://localhost:3001/api/widget'
});

// Check what features are enabled
const info = qualaSdk.getSessionInfo();
console.log('Micro widgets enabled:', info.microWidgetEnabled);

// Debug mode provides additional testing methods
qualaSdk.forceAllowNextWidget(); // Bypass anti-spam
qualaSdk.resetAntiSpamState(); // Reset anti-spam counters
```

## 📚 TypeScript Support

Full TypeScript definitions included:

```typescript
import { qualaSdk, QualaUser, MicroWidgetConfig } from 'quala-widget';

const user: QualaUser = {
  userId: 'user-123',
  email: 'user@company.com'
};

await qualaSdk.identifyUser(user);
```


**Ready to turn vague complaints into actionable insights?** 🚀

Get started at [getquala.xyz](https://getquala.xyz)