Subscriptions
Introduction
The subscription feature enables customers to subscribe to a specific variant of a product, which is then delivered at regular intervals on a chosen day. This convenience allows customers to make regular purchases effortlessly. This Add-on will be pre-installed in the Boilerplate (1.0.0-rc.8 and later).
Configuration
To activate the subscription feature, several preliminary steps are required. Initially, it's essential to configure an environment variable at runtime within the Nuxt configuration. This setup involves specifying two web hosts—one for the overview page and another for the cancellation page—alongside a variable dedicated to the API.
export default defineNuxtConfig({
/* ... */
runtimeConfig: {
/* ... */
public: {
/* ... */
subscription: {
overviewWebHost: process.env.NUXT_PUBLIC_SUBSCRIPTION_OVERVIEW_WEB_HOST ?? '', // Override: NUXT_PUBLIC_SUBSCRIPTION_OVERVIEW_WEB_HOST
cancellationWebHost: process.env.NUXT_PUBLIC_SUBSCRIPTION_CANCELLATION_WEB_HOST ?? '', // Override: NUXT_PUBLIC_SUBSCRIPTION_OVERVIEW_WEB_HOST
apiUrl: process.env.NUXT_PUBLIC_SUBSCRIPTION_API_URL ?? '', // Override: NUXT_PUBLIC_SUBSCRIPTION_API_URL
},
/* ... */
},
/* ... */
},
subscription: {
overviewPagePath: '/path/to/overview',
cancellationPagePath: '/path/to/cancellation',
},
/* ... */
})
Additionally, there is an option to customize the paths for the overview and cancellation pages through the modules configuration.
overviewPagePath
type: string
default: /account/subscription
cancellationPagePath
type: string
default: /account/subscription-cancellation
How does it work?
Component
The component is set up and ready for use. To utilize the component, it is necessary to supply both the product and the currently selected variant.
<ProductSubscription
v-if="isProductSubscriptionEligible(product)"
:product="product"
:variant="activeVariant"
@add-item-to-basket="addItemToBasket($event)"
/>
The function isProductSubscriptionEligible
, sourced from subscription/helpers/subscription.ts
, verifies the product's eligibility for subscription.
Optional Properties
preferredDeliveryDate
To customize the delivery dates, you can provide an array of dates. The label utilizes an i18n-key that incorporates a variable for the day, allowing the day to be dynamically inserted into the label.
type:
type PreferredDeliveryDate = {
day: number
label: string
}
pricePromotionKey
type: string
default: subscription
Composable
The composable facilitates custom development of the Subscription component, enabling the integration of product details, pricePromotionKey, and variant information to generate all essential data for displaying subscription details.
async function useSubscription(
product: Ref<Product>,
pricePromotionKey: Ref<string>,
variant: Ref<Variant | undefined>,
)
const {
subscriptionProduct,
subscriptionIntervals,
subscriptionPrice,
subscriptionVariantEligible,
selectedVariant,
selectedInterval,
selectedPreferredDeliveryDate,
itemToAdd,
totalReductions,
ordinalSuffixKey,
} = await useSubscription(product, pricePromotionKey, variant)
subscriptionProduct
Product data fetched with subscription attributes
type: Ref<Product> | undefined
subscriptionIntervals
Delivery Interval of the selectedVariant
type: ComputedRef<Value[]>
subscriptionPrice
Price of the selected variant
type: Ref<Price> | undefined
subscriptionVariantEligible
Eligibility of the variant for subscription
type: ComputedRef<boolean>
selectedVariant
Active subscription variant
type: ComputedRef<Variant | undefined>
selectedInterval
Active interval
type: Ref<Value | undefined>
selectedPreferredDeliveryDate
Active preferred delivery date
type: Ref<PrefferedDeliveryDate | undefined>
itemToAdd
Object used for AddToBasket
event
type
{
variantId: number
quantity: number
customData: {
subscriptionDefinition: {
subscriptionInterval: string
subscriptionDeliveryDate: number
subscriptionTerm: string
subscriptionCancellationPolicy: string
}
pricePromotionKey: string
}
displayData: {
'attribute-1': {
key: string
label: string
value: string
}
}
}
totalReductions
Precentage of the price reduction
type: ComputedRef<number>
ordinalSuffixKey
Ordinal suffix for the selectedPreferredDeliveryDate
type: ComputedRef<Intl.LDMLPluralRule>
Pages
The Subscription Add-on features two pages that are implemented as Web Components. These pages are loaded via scripts, with their web hosts configured in the Nuxt Configuration under Public Runtime Config. (See #configuration)
Overview Page
const {
isSubscriptionWebComponentLoaded,
isSubscriptionCancellationWebComponentLoaded,
apiUrl
} = useSubscriptionWebComponent()
<subscription-overview
v-if="isSubscriptionWebComponentLoaded"
:base-url="apiUrl"
:customer-token="accessToken"
:shop-id="shopId"
/>
Cancellation Page
<subscription-cancellation
v-if="isSubscriptionCancellationWebComponentLoaded"
:base-url="apiUrl"
:shop-id="shopId"
/>
Contrary to the overview page, the cancellation page does not require the customer's access token, as it needs to be accessible without the necessity for login. Please take this into account when setting up route protection.
I18n-Keys
The default subscription component requires specific i18n keys to display the correct labels.
"subscription": {
"title": "Subscription",
"one_time_purchase": "One-Time Purchase",
"subscribe": "Subscribe & Save",
"subscribe_with_reduction": "Subscribe & Save up to {percentage}%",
"interval": "Interval",
"choose_interval": "Choose Interval",
"follow_up_delivery": "Follow-up delivery",
"day_of_month_selection_caption": "Ever {dayOfMonth} of the month",
"or": "Or save even more:",
"select_size_message": "Select size to see options",
"not_eligible_message": "The selected size is not eligible for a subscription",
"term": "Term",
"add_to_basket": "Subscribe for {interval}"
},
The label for the subscription interval is sourced from the 'subscriptionAvailableIntervals' attribute of the subscription variant.
Known issues
Currently, there are challenges in managing the Add to Basket functionality. Complications arise with items being added to the basket as both subscription and non-subscription types. Consequently, it is necessary to verify if an item has already been added as a subscription type and to issue an error if there's an attempt to add it as a non-subscription type. We provide a helper function for this topic which can be used to prevent this to happen.
const isSubscriptionAlreadyInBasket = (
isSubscriptionVariant: boolean,
variantId: number,
basketItems?: BasketItem[],
): boolean