npm package: @getspot/spot-widget-vue
Description: Vue 3 wrapper for Spot Widget
Latest version: 4.1.1

# @getspot/spot-widget-vue

Vue 3 component wrapper for the Spot refund guarantee widget.

> **Note:** This Vue wrapper uses types from [@getspot/spot-widget](https://www.npmjs.com/package/@getspot/spot-widget).

### Key Types
- `ApiConfig` - API configuration (environment, partnerId, customEndpoint)
- `QuoteRequestData` - Quote request data for single items or batch requests
- `SelectionData` - User selection data returned in callbacks
- `Quote` - Quote response data with pricing and terms
- `Theme` - Styling customization options

For complete type definitions, see the [@getspot/spot-widget documentation](https://www.npmjs.com/package/@getspot/spot-widget).

## Installation

```bash
npm install @getspot/spot-widget-vue
```

## Quick Start

```vue
<template>
  <VueSpotWidget
    :api-config="{
      environment: 'production',
      partnerId: 'your-partner-id'
    }"
    :quote-request-data="quoteData"
    :show-table="true"
    :selection="'unselected'"
    @quote-retrieved="onQuoteRetrieved"
    @opt-in="onOptIn"
    @opt-out="onOptOut"
    @error="onError"
  />
</template>

<script setup>
import VueSpotWidget from '@getspot/spot-widget-vue';

const quoteData = {
  startDate: '2024-01-01T00:00:00Z',
  endDate: '2024-01-07T23:59:59Z',
  currencyCode: 'USD',
  eventType: 'Ski Trip',
  productType: 'Trip',
  productDuration: 'Trip',
  productPrice: 500,
  productId: 'ski-trip-2024',
  cartId: 'cart-123',
  productName: 'Aspen Ski Trip 2024'
};

const onQuoteRetrieved = (quote) => {
  console.log('Quote retrieved:', quote);
};

const onOptIn = (data) => {
  console.log('User opted in:', data);
  // Handle opt-in logic
};

const onOptOut = (data) => {
  console.log('User opted out:', data);
  // Handle opt-out logic
};

const onError = (error) => {
  console.error('Widget error:', error);
  // Handle errors
};
</script>
```

## TypeScript Support

This package includes full TypeScript definitions for Vue 3.

```vue
<script setup lang="ts">
import VueSpotWidget from '@getspot/spot-widget-vue';
import type { Quote, SelectionData } from '@getspot/spot-widget';

interface QuoteData {
  startDate: string;
  endDate: string;
  currencyCode: 'USD' | 'CAD' | 'AUD';
  eventType: string;
  productType: 'Pass' | 'Trip' | 'Registration';
  productDuration: 'Daily' | 'Seasonal' | 'Trip' | 'Event';
  productPrice: number;
  productId: string;
  cartId: string;
  productName: string;
}

const quoteData: QuoteData = {
  // ... your quote data
};

const onQuoteRetrieved = (quote: Quote) => {
  console.log('Quote retrieved:', quote);
};

const onOptIn = (data: SelectionData) => {
  console.log('User opted in:', data);
};

const onOptOut = (data: SelectionData) => {
  console.log('User opted out:', data);
};
</script>
```

## Props

### Required Props

| Prop | Type | Description |
|------|------|-------------|
| `apiConfig` | `ApiConfig` | Configuration for the Spot API including environment and partner ID |
| `quoteRequestData` | `QuoteRequestData` | Quote request data containing product and cart information |

### Optional Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `showTable` | `boolean` | `true` | Whether to show the payout table |
| `selection` | `SelectionEnum` | `'unselected'` | Initial selection state for the widget |
| `theme` | `Theme` | `undefined` | Theme customization options for styling the widget |

## Events

The component emits the following events:

### @quote-retrieved

Emitted when a quote is successfully retrieved.

```vue
<VueSpotWidget @quote-retrieved="onQuoteRetrieved" />
```

**Payload:** `Quote` object

### @opt-in

Emitted when user opts in to the refund guarantee.

```vue
<VueSpotWidget @opt-in="onOptIn" />
```

**Payload:** `SelectionData` object with `status: 'QUOTE_ACCEPTED'`

### @opt-out

Emitted when user opts out of the refund guarantee.

```vue
<VueSpotWidget @opt-out="onOptOut" />
```

**Payload:** `SelectionData` object with `status: 'QUOTE_DECLINED'`

### @error

Emitted when an error occurs during quote retrieval.

```vue
<VueSpotWidget @error="onError" />
```

**Payload:** Error object with `message`, `status`, and `responseBody`

### @no-matching-quote

Emitted when no matching quote is found.

```vue
<VueSpotWidget @no-matching-quote="onNoMatchingQuote" />
```

**Payload:** Object with `status: 'NO_MATCHING_QUOTE'` and original request data

### @selection-change

Emitted when user changes their selection (opt-in or opt-out).

```vue
<VueSpotWidget @selection-change="onSelectionChange" />
```

**Payload:** `SelectionData` object

## Exposed Methods

You can access widget methods using template refs:

```vue
<template>
  <div>
    <VueSpotWidget
      ref="spotWidget"
      v-bind="widgetProps"
    />
    <button @click="updateQuote">Update Quote</button>
    <button @click="getSelection">Get Selection</button>
    <button @click="validateSelection">Validate Selection</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import VueSpotWidget from '@getspot/spot-widget-vue';

const spotWidget = ref();

const updateQuote = async () => {
  const success = await spotWidget.value?.updateQuote({
    // new quote data
  });
  console.log('Quote updated:', success);
};

const getSelection = () => {
  const selection = spotWidget.value?.getSelection();
  console.log('Current selection:', selection);
};

const validateSelection = () => {
  const isValid = spotWidget.value?.validateSelection();
  console.log('Selection is valid:', isValid);
};
</script>
```

### Available Methods

| Method | Return Type | Description |
|--------|-------------|-------------|
| `updateQuote(data)` | `Promise<boolean>` | Update the quote with new request data |
| `getSelection()` | `SelectionData \| null` | Get the current user selection |
| `validateSelection()` | `boolean` | Validate that the user has made a selection |
| `destroy()` | `void` | Destroy the widget instance and clean up resources |

## Configuration

### API Configuration

The `apiConfig` prop accepts the following options:

```typescript
{
  environment: 'production' | 'sandbox' | 'local',
  partnerId: string,
  customEndpoint?: string // Optional custom API endpoint
}
```

### Quote Request Data

#### Single Quote Format

```typescript
{
  startDate: string,        // ISO 8601 date string
  endDate: string,          // ISO 8601 date string  
  currencyCode: 'USD' | 'CAD' | 'AUD',
  eventType: string,        // e.g., "Ski Trip", "Concert"
  productType: 'Pass' | 'Trip' | 'Registration',
  productDuration: 'Daily' | 'Seasonal' | 'Trip' | 'Event',
  productPrice: number,     // Price in specified currency
  productId: string,        // Unique product identifier
  cartId: string,           // Cart identifier
  productName: string,      // Human-readable product name
  participantDescription?: string // Optional participant details
}
```

#### Batch Quote Format

For multiple items in a cart:

```typescript
{
  cartId: string,
  cartName: string,
  currencyCode: 'USD' | 'CAD' | 'AUD',
  items: Array<{
    // Same fields as single quote, minus cartId and currencyCode
    cartItemId?: string // Optional unique identifier for cart item
  }>
}
```

## Styling

Customize the widget appearance using the `theme` prop:

```vue
<template>
  <VueSpotWidget
    :theme="{
      primaryColor: '#007bff',
      borderRadius: '8px',
      fontFamily: 'Arial, sans-serif'
    }"
    v-bind="otherProps"
  />
</template>
```

## Options API Usage

If you prefer the Options API:

```vue
<template>
  <VueSpotWidget
    :api-config="apiConfig"
    :quote-request-data="quoteRequestData"
    @opt-in="handleOptIn"
    @opt-out="handleOptOut"
    @error="handleError"
  />
</template>

<script>
import VueSpotWidget from '@getspot/spot-widget-vue';

export default {
  components: {
    VueSpotWidget
  },
  
  data() {
    return {
      apiConfig: {
        environment: 'production',
        partnerId: 'your-partner-id'
      },
      quoteRequestData: {
        startDate: '2024-01-01T00:00:00Z',
        endDate: '2024-01-07T23:59:59Z',
        currencyCode: 'USD',
        eventType: 'Test Event',
        productType: 'Trip',
        productDuration: 'Trip',
        productPrice: 100,
        productId: 'test-product',
        cartId: 'test-cart',
        productName: 'Test Product'
      }
    };
  },
  
  methods: {
    handleOptIn(data) {
      console.log('User opted in:', data);
      // Handle opt-in logic
    },
    
    handleOptOut(data) {
      console.log('User opted out:', data);
      // Handle opt-out logic
    },
    
    handleError(error) {
      console.error('Widget error:', error);
      // Handle error
    }
  }
};
</script>
```

## Error Handling

Always implement error handling for production use:

```vue
<template>
  <div>
    <VueSpotWidget
      v-bind="widgetProps"
      @error="handleError"
      @no-matching-quote="handleNoQuote"
    />
    <div v-if="errorMessage" class="error-message">
      {{ errorMessage }}
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const errorMessage = ref('');

const handleError = (error) => {
  console.error('Spot Widget Error:', error);
  
  // Show user-friendly message
  errorMessage.value = 'Unable to load refund options. Please try again.';
  
  // Track error in analytics
  if (window.analytics) {
    window.analytics.track('spot_widget_error', {
      message: error.message,
      status: error.status
    });
  }
};

const handleNoQuote = () => {
  errorMessage.value = 'No refund guarantee available for this product.';
};
</script>
```

## Compatibility

- **Vue**: 3.x
- **TypeScript**: 5.x  
- **Node.js**: 16+

## License

See the main package for license information.

## Support

For support, please contact [support@getspot.com](mailto:support@getspot.com).