@eparts/canopyalpsconfigurator
v1.0.53
Published
Vue/Nuxt configurable product component for Canopy Alps platforms
Maintainers
Keywords
Readme
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/epartsconfiguratorOr with pnpm (recommended for Nuxt 4):
pnpm add @eparts/epartsconfiguratorUsage 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('[email protected]')
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-checkLicense
ISC
Support
For issues or questions, contact: [email protected]
