npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

brandlabs-bigcommerce-wishlist

v0.1.0

Published

Easy-to-use wishlist functionality for BigCommerce themes.

Downloads

44

Readme

BigCommerce Wishlist

Easy-to-use Wishlist functionality for BigCommerce themes.

This package provides simple JavaScript methods to:

  • Check if a product has already been added to a wishlist.
  • Add or remove a product from a wishlist.
  • Create, update or remove wishlists.
  • Get wishlists details.
  • Event listeners for changes on wishlists.

In this document:

Info

  • URL: https://github.com/brandlabs/bigcommerce-wishlist
  • Platform: BigCommerce

Setup

Install package

Install the package as a dependency of your Stencil theme:

npm install brandlabs-bigcommerce-wishlist --save-dev

Required template

The post install script will create a Handlebars template file named json-this.html in your Stencil theme at templates/components/custom folder.

This template file is required for the package to work

Use it in theme

  • Import the package and you'll get a WishlistManager instance.
  • Provide context to the init method. (optional)
  • Use the available methods.
import wishlistManager from 'brandlabs-bigcommerce-wishlist';

export default class ProductDetails {
    constructor($scope, context, productAttributesData = {}) {
        // ...
        this.showAddedToWishlist();
    }

    async showAddedToWishlist() {
        // Initialize
        await wishlistManager.init(this.context);

        const productId = $('input[name="product_id"]', this.$scope).val();

        // Check if product belongs to one of the customer's wishlists
        const isAddedToWishlist = await wishlistManager.isProductInAnyWishlist(productId);

        if (isAddedToWishlist) {
            $('.added-to-wishlist').show();
        } else {
            $('.added-to-wishlist').hide();
        }
    }
}

Try it yourself

To quickly try it from browser, simply add these two lines to assets/js/theme/global.js:

// Append this line to the imports:
import wishlistManager from 'brandlabs-bigcommerce-wishlist';

export default class Global extends PageManager {
    onReady() {
        // Add this line so you can use the wishlistManager as "wm" from console:
        window.wm = wishlistManager;
    }
}

Perform login as a customer into the store, and the wm (wishlist manager) functionality will be available from Dev Tools console to create, update and remove wishlists, add and remove products from wishlists, etc.

Use console.log as argument to Promise's then, to see the results:

wm.getAllWishlists().then(console.log)

ECMAScript 6

The source code from this package is written using ES6 features.

Default Webpack configuration from Cornerstone theme uses Babel to transpile ES6 code within assets/js folder. It does not transpile ES6 code from node_modules.

To get the transpiled code for this package in your theme bundle, there are three options.

Choose one of them:

  1. Import the transpiled version from dist folder:
import wishlistManager from 'brandlabs-bigcommerce-wishlist/dist/wishlist-manager.min.js';
  1. Include brandlabs-bigcommerce-wishlist in the paths to transpile. At webpack.common.js, update the include regular expression:
module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                include: /(assets\/js|assets\\js|stencil-utils|brandlabs-bigcommerce-wishlist)/,
  1. Use an alias for the dist version. At webpack.common.js, add one entry for the wishlist package:
module.exports = {
    resolve: {
        alias: {
            'brandlabs-bigcommerce-wishlist': path.resolve(__dirname, 'node_modules/brandlabs-bigcommerce-wishlist/dist/wishlist-manager.min.js'),

API Reference

The main functionality mimics the BigCommerce Wishlist API:

Wishlist API

Most methods are asynchronous, returning a Promise which will resolve into the expected result, or reject upon an error.

METHODS

  • getAllWishlists - Get all wishlists for the current customer.
  • getWishlist - Get specified wishlist details for the current customer.
  • createWishlist - Create a new wishlist for the current customer.
  • deleteWishlist - Remove a wishlist from the current customer.
  • updateWishlist - Update a wishlist for the current customer.
  • addWishlistItem - Add a product to a customer wishlist.
  • deleteWishlistItem - Remove a product from a customer wishlist.
  • getAllWishlistsDetails - Get all wishlists for the current customer, including the list of items for each one of them.
  • isProductInAnyWishlist - Verify if a specific product belongs to any of the customer's wishlists.
  • on - Register an event listener.
  • off - Remove an event listener.
  • init - Initialize the instance with optional context data.

PROPERTIES

:warning: Note: In the examples below, we provide both one then callback and one event listener, to illustrate how to use them. It is not necessary to use both in real applications. Please choose the option which fits better to your use case.

# async getAllWishlists(forceFetch = false)

Get all wishlists for the current customer.

Arguments:
  • {boolean} forceFetch - True to ignore the cache, False otherwise. Defaults to false.
Returns:
  • {Promise<array>} wishlists
Usage:

Each object in the returned array shall contain the following properties:

  • id
  • name
  • is_public
  • num_items
  • token
  • view_url
  • edit_url
  • delete_url
  • share_url
  • add_url
wm.getAllWishlists().then(wishlists => {
    const totalNumberOfItems = wishlists.reduce((total, { num_items }) => total + num_items, 0);
    console.log(`Total number of items in all wishlists is ${totalNumberOfItems}`);
});

# async getWishlist(wishlistid, forceFetch = false)

Get specified wishlist details for the current customer.

Arguments:
  • {integer} wishlistid - Wishlist ID.
  • {boolean} forceFetch - True to ignore the cache, False otherwise. Defaults to false.
Returns:
  • {Promise<object>} wishlist
Usage:

The returned object shall contain the following properties:

  • id
  • name
  • is_public
  • is_editable
  • items
  • token
  • share_url

Note that the properties returned from getWishlist differ from the properties returned from getAllWishlists.

This is not a "feature" of the package. This reflects what is actually returned from BigCommerce server.

While the wishlist objects returned from getAllWishlists provide the number of items as num_items, the object returned from getWishlist contains an items array with the actual items.

wm.getWishlist(9).then(({ name, items, is_public, share_url }) => {
    console.log(`The "${name}" wishlist contains ${items.length} item${items.length === 1 ? '' : 's'}.`);
    if (is_public) {
        console.log(`It can be shared through this URL: ${share_url}`);
    } else {
        console.log(`It is a private list.`);
    }
});

# async createWishlist({ name, is_public, product_id })

Create a new wishlist for the current customer.

Arguments:
  • {Object} params - The wishlist attributes.
    • {string} name - Wishlist name (required).
    • {boolean} is_public - Indicates if wishlist is public. Defaults to false.
    • {integer} product_id - ID of a product to be added to the wishlist (optional).
Returns:
  • {Promise<object>} wishlist
Fires:
  • createWishlist({ wishlist }) event
Usage:

The returned wishlist object varies:

  • If no product_id is provided, then it will contain the same properties returned by getAllWishlists
  • If a product_id is provided, then it will contain the same properties returned by getWishlist

The createWishlist event is triggered. The event handler function is called immediately before the Promise is resolved.

wm.on('createWishlist', ({ wishlist }) => {
    console.log(`Wishlist "${wishlist.name}" has been created.`);
});

wm.createWishlist({ name: 'Best Wishes' }).then(({ id }) => {
    console.log(`The ID for the new wishlist is ${id}.`);
});

# async deleteWishlist(wishlistid)

Remove a wishlist from the current customer.

Arguments:
  • {integer} wishlistid - Wishlist ID.
Returns:
  • {Promise<undefined>}
Fires:
  • deleteWishlist({ wishlistid }) event
Usage:

The deleteWishlist event is triggered. The event handler function is called immediately before the Promise is resolved.

wm.on('deleteWishlist', ({ wishlistid }) => {
    console.log(`Wishlist ID ${wishlistid} has been deleted.`);
});

wm.deleteWishlist(17).then(() => alert('Wishlist deleted!')).catch(error => {
    console.log(`Something went wrong when trying to delete the wishlist.`);
});

# async updateWishlist(wishlistid, { name, is_public })

Update a wishlist for the current customer.

Arguments:
  • {integer} wishlistid - Wishlist ID.
  • {Object} params - The wishlist attributes.
    • {string} name - Wishlist name (required).
    • {boolean} is_public - Indicates if wishlist is public (required).
Returns:
  • {Promise<object>} wishlist
Fires:
  • updateWishlist({ wishlist }) event
Usage:

Both arguments (name and is_public) will always be updated. Even if you want to change only one of them, and keep the other, you need to provide values for both name and is_public. Otherwise, the name will be set to an empty string, and is_public will be set to false.

The returned wishlist object contains the same properties returned in getAllWishlists

The updateWishlist event is triggered. The event handler function is called immediately before the Promise is resolved.

wm.on('updateWishlist', ({ wishlist }) => {
    console.log(`Wishlist ID "${wishlist.id}" has been updated.`);
});

wm.updateWishlist(9, { name: 'New Wishes', is_public: true }).then(({ name, is_public }) => {
    console.log(`Updated wishlist attributes: name = "${name}", is_public = ${is_public ? 'true' : 'false'}.`);
});

# async addWishlistItem(wishlistid, product_id)

Add a product to a customer wishlist.

Arguments:
  • {integer} wishlistid - Wishlist ID.
  • {integer} product_id - ID of a product to be added to the wishlist.
Returns:
  • {Promise<item>}
Fires:
  • addWishlistItem({ wishlist, item }) event
Usage:

The addWishlistItem event is triggered. The event handler function is called immediately before the Promise is resolved.

The returned item object contains several product properties, including product_id, name and sku. It contains also its own id.

wm.on('addWishlistItem', ({ wishlist, item }) => {
    console.log(`Product "${item.name}" added to wishlist "${wishlist.name}".`);
});

wm.addWishlistItem(9, 15).then(item => {
    console.log(item);
});

# async deleteWishlistItem(wishlistid, item_id)

Remove a product from a customer wishlist.

Arguments:
  • {integer} wishlistid - Wishlist ID.
  • {integer} item_id - Wishlist item ID.
Returns:
  • {Promise<undefined>}
Fires:
  • deleteWishlistItem({ wishlistid, item_id }) event
Usage:

The deleteWishlistItem event is triggered. The event handler function is called immediately before the Promise is resolved.

wm.on('deleteWishlistItem', ({ wishlistid, item_id }) => {
    console.log(`Item ID ${item_id} from Wishlist ID ${wishlistid} has been removed.`);
    const wishlist = wm.wishlists[wishlistid];
    console.log(`Wishlist "${wishlist.name}" contains ${wishlist.num_items} items now.`);
});

wm.deleteWishlistItem(9, 23).then(() => alert('Wishlist item deleted!')).catch(error => {
    console.log(`Something went wrong when trying to remove item from wishlist.`);
});

# async getAllWishlistsDetails()

Get all wishlists for the current customer, including the list of items for each one of them.

Returns:
  • {Promise<array>} wishlists
Usage:

Each object in the returned array shall contain the following properties:

  • id
  • name
  • is_public
  • is_editable
  • items
  • num_items
  • token
  • view_url
  • edit_url
  • delete_url
  • share_url
  • add_url
wm.getAllWishlistsDetails().then(wishlists => {
    const totalNumberOfItems = wishlists.reduce((total, { items }) => total + items.length, 0);
    console.log(`Total number of items in all wishlists is ${totalNumberOfItems}`);
});

# async isProductInAnyWishlist(product_id)

Verify if a specific product belongs to any of the customer's wishlists.

Returns:
  • {Promise<boolean>} belongs
Usage:

The Promise resolves to True if the specified product ID belongs to any wishlist, False otherwise.

const product_id = 15;

wm.isProductInAnyWishlist(product_id).then(wished => {
    console.log(`Product ID ${product_id} is ${wished ? 'a wished product!' : 'not in any wishlist.'}`);
});

# on(name, callback)

Register an event listener.

Arguments:
  • {string} name - The event name.
  • {Function} callback - The function to run when the event is triggered.
Usage:

All methods which changes the wishlists trigger events.

See the reference of each method for details on the provided event parameters:

const onCreateWishlist = ({ wishlist }) => {
    console.log(`A new ${wishlist.is_public ? 'public' : 'private' } wishlist called "${wishlist.name}" has been created.`);
};

wm.on('createWishlist', onCreateWishlist);

# off(name, callback)

Remove an event listener.

Arguments:
  • {string} name - The event name.
  • {Function} callback - The function to be removed from listeners.
Usage:

In order to be able to remove an event listener, it is important to have a reference to it.

So, if your code will remove event listeners, it is better to avoid anonymous functions when registering them.

// GOOD EXAMPLE:
const onCreateWishlist = ({ wishlist }) => {
    console.log(`A new ${wishlist.is_public ? 'public' : 'private'} wishlist called "${wishlist.name}" has been created.`);
};

wm.on('createWishlist', onCreateWishlist);

wm.off('createWishlist', onCreateWishlist);

// AVOID USING ANONYMOUS FUNCTIONS:
wm.on('deleteWishlist', () => console.log('A wishlist has been removed.'));

wm.off('deleteWishlist', wm.eventListeners['deleteWishlist'][0]); // Not reliable. Not recommended.

# async init({ wishlists, urls } = {})

Initialize the instance with optional context data.

Arguments:
  • {Object} context - Stencil context.
    • {array} wishlists - Wishlists.
    • {object} urls - URLs.
Usage:

The call to init method is not mandatory. It is optional. The context parameter is also optional.

This is exactly what init does:

    // Use wishlists URLs from context
    if (urls && urls.account && urls.account.wishlists) {
        Object.assign(this.urls, urls.account.wishlists);
    }

    // Cache warming
    if (this.useCache) {
        this.getAllWishlistsFromCache();
    }

    // Initial wishlists fetch, if not available in context
    if (Array.isArray(wishlists)) {
        this.setWishlists(wishlists);
    } else {
        await this.getAllWishlists(true);
    }

:one: Stencil context usually contains wishlists URL information, at context.urls.account.wishlists. The init method will configure the instance to use the context URLs. This usually will make no difference at all, since the configured defaults correspond to the values used by all BigCommerce stores.

:two: Loads data from cache into the instance's wishlists property.

:three: If a wishlists array is provided in context, it will be used as initial source of truth, populating the instance's wishlists property data. Otherwise, an AJAX call to BigCommerce will be made to retrieve the initial wishlists data.

Thus, this initial HTTP request to BigCommerce server can be avoided if wishlists is injected into the context. This can be achieved from the Handlebars page templates in the theme. This is done through a front-matter entry, and the usage of Handlebars inject helper, like this:

---
customer:
   wishlists:
     limit:10
---
{{inject "wishlists" customer.wishlists}}

# wm.useCache

  • Type: boolean

  • Default: true

  • Details: From the moment this is set to false, the cache will not be read anymore. If set to true, the cache will be available for reading. This setting does not affect the write operations to the cache.

// To completely skip reading cache, turn it off before calling init
wm.useCache = false;
wm.init(this.context);

# wm.cacheDuration

  • Type: integer

  • Default: 60

  • Details: Time to expire cached data, in minutes. This does not imply on cache data deletion. If there is data stored in cache 90 minutes ago, it will be discarded when reading. In this case, if cacheDuration is modified to 120, the next cache read operations will not discard anumore the data which has been stored in cache 90 minutes ago.

// It is recommended to set the preferred value for cacheDuration before calling init
wm.cacheDuration = 360;
wm.init(this.context);

# wm.urls

  • Type: object

  • Default:

{
    base: window.location.origin,
    all: '/wishlist.php',
    add: '/wishlist.php?action=addwishlist',
    edit: '/wishlist.php?action=editwishlist',
    delete: '/wishlist.php?action=deletewishlist',
    view: '/wishlist.php?action=viewwishlistitems',
    add_item: '/wishlist.php?action=add',
    delete_item: '/wishlist.php?action=remove',
    share: '/wishlist.php?action=sharewishlist',
}
  • Details: URLs used for the remote AJAX requests. They can be changed/configured.
// Use a test or proxy domain to receive the requests
wm.urls.base = 'https://example.com';

# wm.events

  • Type: object

  • Default:

{
    createWishlist: 'createWishlist',
    deleteWishlist: 'deleteWishlist',
    updateWishlist: 'updateWishlist',
    addWishlistItem: 'addWishlistItem',
    deleteWishlistItem: 'deleteWishlistItem',
}
  • Details: Instead of using hard-coded strings, it is possible to refer the events from this object property. The event names can also be changed/configured.
wm.events.createWishlist = 'wishlistCreated';
wm.events.deleteWishlist = 'wishlistDeleted';

wm.on('wishlistCreated', () => 'A wishlist has been created.');
wm.on(wm.events.deleteWishlist, () => 'A wishlist has been deleted.');

wm.on(wm.events.updateWishlist, () => 'A wishlist has been updated.');

# wm.wishlists

  • Type: object

  • Details: Contains all wishlist data read from cache, or from remote requests, or changed via any of the method calls. It always contains the most complete and up-to-date wishlists data the WishlistManager instance is aware of. It is a dictonary keyed by the wishlist ID.

async foo() {
    await wm.getWishlist(5);
    const productIds = wm.wishlists[5].items.map(item => item.product_id);
}

async bar() {
    await wm.getAllWishlistsDetails();
    console.log(wm.wishlists); // ALL data is in here
}

The wishlists property is suitable to be used in a reactive context.

Here is a Vue JS 3 example:

wm.wishlists = Vue.reactive({});
wm.init();

Vue.createApp({
    data: () => ({ wishlists: wm.wishlists }),
    template: `
        <table id="wm">
            <tr><th>ID</th><th>Name</th><th>Shared</th><th>Items</th></tr>
            <tr v-for="wishlist in wishlists">
                <td>{{ wishlist.id }}</td>
                <td>{{ wishlist.name }}</td>
                <td>{{ wishlist.is_public ? 'public' : 'private' }}</td>
                <td v-if="wishlist.items">{{ wishlist.items.map(item => item.name).join(', ') }}</td>
                <td v-else>{{ wishlist.num_items }} item{{ wishlist.num_items === 1 ? '' : 's' }}</td>
            </tr>
        </table>`,
}).mount($('<div>').appendTo('body').get(0));

With this setup, any change done using the "create", "update", "delete", "add item" or "remove item" is automatically reflected in the HTML table, without any then callback, any event listener or any other kind of post-processing.

Maintenance

For development of this package, we use:

  • ESLint for linting JS code
  • Jest for testing
  • Webpack for bundling

Lint

To lint the scripts, run npm run lint

Test

To perform the tests, run npm run test

Bundle

To generate the dist folder and build bundle assets, run npm run build

License

This project is licensed under the MIT License - see the LICENSE file for details

Brand Labs Logo