docs
  1. SCAYLE Resource Center
  2. Developer Guide
  3. Integrations
  4. Subscriptions

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).

Example Product

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": {
  "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 -----",
  "select_size_message": "Select size to see options",
  "not_eligible_message": "The selected size is not eligible for a subscription"
}

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