@eparts/canopyalpsconfigurator

Vue/Nuxt configurable product component for Canopy Alps platforms
1,797
Install
npm install @eparts/canopyalpsconfigurator
Latest Version:1.0.53
Vue:3
License:ISC
Last Updated:Jun 10, 2026
Links: Bitbucket  ·  npm
Maintainer: alexbogues

Eparts Configurator

A Vue 3 / Nuxt 4 compatible product configurator component for eparts platforms. Enables customers to configure complex products with dimensions, options, and pricing in real-time.

Features

  • 🎨 PrimeVue Integration - Built with PrimeVue components and Aura theme
  • 🔧 Configurable Options - Dropdowns, text inputs, dimensions, and custom options
  • 💰 Real-time Pricing - Live price updates as options change
  • 📦 Multi-target - Add to Cart, List, Quote, or Project
  • 🎯 Quick Configure - Pre-configured product templates
  • ✅ Validation - Built-in validation with error messaging
  • 📱 Responsive - Mobile-friendly design
  • 🌙 Dark Mode - Automatic theme support

Requirements

  • Node.js: >= 22.16.0
  • npm: >= 10.9.0
  • Vue: ^3.5.26
  • Pinia: ^3.0.4
  • PrimeVue: ^4.5.4

Installation

npm install @eparts/epartsconfigurator

Or with pnpm (recommended for Nuxt 4):

pnpm add @eparts/epartsconfigurator

Usage in Nuxt 4

1. Register as a Plugin

Create a plugin file plugins/configurator.client.ts:

import { configuratorPlugin } from '@eparts/epartsconfigurator'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(configuratorPlugin)
})

2. Import Styles

Add to your nuxt.config.ts:

export default defineNuxtConfig({
  css: [
    '@eparts/epartsconfigurator/style.css'
  ]
})

Or import in your component/page:

<style>
@import '@eparts/epartsconfigurator/style.css';
</style>

3. Use in Components

Basic Usage
<template>
  <EpartsConfigurator
    :product-guid="productGuid"
    :base-api-url="apiUrl"
    :quantity="1"
    target="Cart"
    @complete="handleComplete"
    @cancel="handleCancel"
    @error="handleError"
  />
</template>

<script setup lang="ts">
import type { ConfiguredProductSelection, ConfiguratorError } from '@eparts/epartsconfigurator'

const productGuid = ref('abc-123-def-456')
const apiUrl = ref('https://api.example.com')

const handleComplete = (selection: ConfiguredProductSelection) => {
  console.log('Configuration complete:', selection)
  // Navigate to cart or show success message
}

const handleCancel = () => {
  console.log('Configuration cancelled')
  // Close modal or navigate away
}

const handleError = (error: ConfiguratorError) => {
  console.error('Configuration error:', error)
  // Show error notification
}
</script>
Modal/Drawer Integration

Create a modal wrapper component components/ConfiguratorModal.vue:

<template>
  <Transition name="modal">
    <div v-if="isOpen" class="modal-overlay" @click.self="close">
      <div class="modal-container">
        <div class="modal-header">
          <h2>Configure Product</h2>
          <button @click="close" class="close-button">×</button>
        </div>
        
        <div class="modal-body">
          <EpartsConfigurator
            v-if="product"
            :product-guid="product.guid"
            :product-id="product.id"
            :base-api-url="apiUrl"
            :quantity="quantity"
            :target="target"
            :support-email="supportEmail"
            @complete="handleComplete"
            @cancel="close"
            @error="handleError"
          />
        </div>
      </div>
    </div>
  </Transition>
</template>

<script setup lang="ts">
import type { ConfiguredProductSelection, ConfiguratorError } from '@eparts/epartsconfigurator'

interface Props {
  isOpen: boolean
  product: {
    id: number
    guid: string
    name: string
  } | null
  apiUrl: string
  quantity?: number
  target?: 'Cart' | 'List' | 'Quote' | 'Project'
  supportEmail?: string
}

const props = withDefaults(defineProps<Props>(), {
  quantity: 1,
  target: 'Cart',
})

const emit = defineEmits<{
  close: []
  complete: [selection: ConfiguredProductSelection]
  error: [error: ConfiguratorError]
}>()

const close = () => {
  emit('close')
}

const handleComplete = (selection: ConfiguredProductSelection) => {
  emit('complete', selection)
  close()
}

const handleError = (error: ConfiguratorError) => {
  emit('error', error)
}
</script>

<style scoped>
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal-container {
  background: white;
  border-radius: 8px;
  max-width: 800px;
  max-height: 90vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.5rem;
  border-bottom: 1px solid #e5e7eb;
}

.modal-body {
  overflow-y: auto;
  padding: 1.5rem;
}

.close-button {
  background: none;
  border: none;
  font-size: 2rem;
  cursor: pointer;
  color: #6b7280;
  line-height: 1;
}

.modal-enter-active,
.modal-leave-active {
  transition: opacity 0.3s ease;
}

.modal-enter-from,
.modal-leave-to {
  opacity: 0;
}
</style>
Using the Modal in a Product Page
<template>
  <div class="product-page">
    <div class="product-info">
      <h1>{{ product.name }}</h1>
      <p>{{ product.description }}</p>
      
      <button 
        v-if="product.isConfigurable"
        @click="openConfigurator"
        class="configure-button"
      >
        Configure Product
      </button>
    </div>

    <ConfiguratorModal
      :is-open="configuratorOpen"
      :product="configuratorProduct"
      :api-url="apiUrl"
      :support-email="supportEmail"
      @close="configuratorOpen = false"
      @complete="handleConfigurationComplete"
      @error="handleConfigurationError"
    />
  </div>
</template>

<script setup lang="ts">
import type { ConfiguredProductSelection, ConfiguratorError } from '@eparts/epartsconfigurator'

const product = ref({
  id: 12345,
  guid: 'abc-123-def-456',
  name: 'Configurable Widget',
  description: 'A highly customizable widget',
  isConfigurable: true,
})

const apiUrl = ref('https://api.example.com')
const supportEmail = ref('support@example.com')
const configuratorOpen = ref(false)

const configuratorProduct = computed(() => 
  configuratorOpen.value ? product.value : null
)

const openConfigurator = () => {
  configuratorOpen.value = true
}

const handleConfigurationComplete = async (selection: ConfiguredProductSelection) => {
  console.log('Product configured:', selection)
  
  // Optional: Add to cart via API
  // await addToCart(selection)
  
  // Show success notification
  // navigateTo('/cart')
}

const handleConfigurationError = (error: ConfiguratorError) => {
  console.error('Configuration error:', error)
  // Show error toast/notification
}
</script>

Props

Prop Type Default Description
productId number - Product ID
productGuid string - Product GUID (required)
baseApiUrl string - Base API URL (required)
quantity number 1 Initial quantity
target 'Cart' | 'List' | 'Quote' | 'Project' 'Cart' Target destination
targetId number - Target ID (for updates)
lineNumber number - Line number (for updates)
targetAction string - Target action
groupingId number - Grouping ID (for projects)
stateId number - State ID
customerToken string - Customer token
guestCartGuid string - Guest cart GUID
isQuickConfigurable boolean false Enable quick configure
isProductDetails boolean false Is product details page
replace boolean false Replace mode
supportEmail string - Support email
phone string - Support phone
saveApiUrl string - Custom save API URL
configuredProductString string - Configured product JSON string
listDetails string - List details JSON
miscId number - Misc ID

Events

complete

Emitted when configuration is successfully completed and saved.

Payload: ConfiguredProductSelection

{
  Quantity: number
  ConfiguredProduct: {
    FormatVersion: string
    ProductGuid: string
    IsProductNumberOverridden: boolean
    OptionalProductNumberOverride?: string
    OptionalTags: string[]
    OptionalDim1: Dimension | null
    OptionalDim2: Dimension | null
    SelectedProductOptions: SelectedProductOption[]
  }
}

cancel

Emitted when user cancels configuration.

Payload: void

error

Emitted when an error occurs during configuration.

Payload: ConfiguratorError

{
  type: 'api' | 'validation' | 'network'
  message: string
  details?: any
}

change

Emitted when configuration changes (for real-time updates).

Payload: ConfiguredProductSelection

priceUpdate

Emitted when price updates.

Payload: PriceUpdate

{
  basePrice: number
  unitPrice: number
  cost: number | null
  totalPrice: number
  productNumber: string
}

Advanced Usage

Direct Store Access

For advanced use cases, you can directly access the Pinia stores:

import { useConfigStore } from '@eparts/epartsconfigurator'

const configStore = useConfigStore()

// Access product options
console.log(configStore.ProductOptions)

// Manually trigger pricing
await configStore.PriceProduct()

// Check if product is in favorites
console.log(configStore.IsInFavoriteParts)

TypeScript Support

Full TypeScript support with exported types:

import type {
  ConfiguratorProps,
  ConfiguredProductSelection,
  ConfiguratorError,
  PriceUpdate,
  ProductOptions,
  Dimension,
  SelectedProductOption,
} from '@eparts/epartsconfigurator'

Styling

The configurator uses PrimeVue components with the Aura theme. You can customize the theme by overriding CSS variables or providing your own PrimeVue theme configuration.

Custom Theme

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@primevue/nuxt-module'],
  primevue: {
    options: {
      theme: {
        preset: YourCustomTheme,
        options: {
          darkModeSelector: '.dark-mode',
          cssLayer: {
            name: 'primevue',
            order: 'tailwind-base, primevue, tailwind-utilities'
          }
        }
      }
    }
  }
})

Development

# Install dependencies
npm install

# Run development server
npm run dev

# Build library
npm run build

# Run tests
npm run test:unit

# Type check
npm run type-check

License

ISC

Support

For issues or questions, contact: support@epartsservices.com

Related Packages

@eparts/eparts-vue-select

Everything you wish the HTML element could do, wrapped up into a lightweight, ex...

857

Version History

Version Released Vue License
1.0.53 ^3.5.26 ISC
1.0.47 ^3.5.26 ISC
1.0.43 ^3.5.26 ISC
1.0.38 ^3.5.26 ISC
1.0.29 ^3.5.26 ISC