@timbouc/cart
v0.2.3
Published
A flexible and fluent way to manage shopping carts.
Downloads
18
Maintainers
Readme
@timbouc/cart
A Shopping Cart Implementation for Node.js and browsers.
:yellow_heart: Features
- Pluggable storage drivers
- Manage vouchers, shipping and other conditional factors with Conditions
- Sync frontend and backend instances with remote storage connection
- Comes with a default local storage (Node.js)
- Save miscellaneous data to cart (e.g. currency, purchase metadata)
- Customise final items' and conditions' prices with
hooks
for complex (e.g. graduated pricing) use case
Getting Started
This package is available in the npm registry.
It can easily be installed with npm
or yarn
.
$ npm i @timbouc/cart
# or
$ yarn add @timbouc/cart
Instantiate with a configuration.
import { Cart } from '@timbouc/cart';
const cart = new Cart(context.uudid, config);
Usage
const item = await cart.add({
id: product.id,
name: product.name,
price: product.price,
});
await cart.apply([
{
name: 'Voucher 1',
type: 'voucher',
target: item.item_id,
value: '-10%', // removes 10% of the value of product.price
},
{
name: 'Shipping',
type: 'shipping',
target: 'subtotal', // add 10 to subtotal
value: 10,
}
]);
const subtotal = await cart.subtotal(),
total = await cart.total();
Registering Storage
const { RedisStorage, PostgresStorage } from './StorageDrivers';
const session = context.uudid
const cart = new Cart(session, config)
cart.registerDriver('redis', RedisStorage)
cart.registerDriver('pg', PostgresStorage())
// use redis storage for different shopping carts
cart.driver('redis')
.add(...)
// use postgres storage for wishlist
cart.driver('pg')
.session(session + ':wishlist') // can also change session (user)
.add(...)
See RedisStorage example from custom storage.
Response interface
Asynchronous methods will always return a Promise which resolves with a Response
object.
Methods
// Set/switch cart session instance
cart.session(user_id)
.add(...)
Add an item or an array of items to cart
// add one item to cart
const item = await cart.add({
// item_id: 1, // Manually set item id
id: product.id,
name: product.name,
price: product.price,
quantity: 3, // defaults to one
conditions: conditions as Array<CartCondition>,
options: options as Array<CartItemOption>,
})
// add multiple items to cart
const [item1, item2] = await cart.add([
{
id: product1.id,
name: product1.name,
price: product1.price,
options: [{
name: "Color",
value: "pink",
}]
},
{
id: product2.id,
name: product2.name,
price: product2.price,
},
])
// Add item with custom field(s)
// cannot be updated afterwords
const item = await cart.add({
id: product.id,
name: product.name,
price: product.price,
workspace: 'Timbouc',
})
Update a cart item. Accumulates quantity by default but override can be specified
// new item price, price can also be a string format like so: '98.67'
cart.update(5, {
name: 'New Item Name',
price: 99.99,
});
// update a product's quantity
cart.update(5, {
quantity: 2, // if the current product has a quantity of 4, another 2 will be added so this will result to 6
});
// update a product by reducing its quantity
cart.update(5, {
quantity: -1, // if the current product has a quantity of 4, another 1 will be subtracted so this will result to 3
});
// To totally replace the quantity instead of incrementing or decrementing its current quantity value
// pass an object
cart.update(5, {
quantity: {
relative: false,
value: 5
}
});
Remove an item or an array of items from cart
cart.remove(5);
// Remove multiple
cart.remove([2, 3, 4]);
// Get cart item
const item = await cart.get(item_id);
Apply a cart condition or an array of conditions. Conditions are used to account for discounts, taxes and other conditional factors.
The field target
specifies the entity the condition applies to. This value can be total
, subtotal
or an item ID.
const voucher1 = await cart.apply({
name: 'Voucher 1',
type: 'voucher',
target: 1, // cart item id
value: -10, // removes the value `10` from i1
});
// apply multiple conditions
const [voucher1b, tax] = await cart.apply([
{
name: 'Voucher 1', // Replaces `Voucher 1` as it already exists (handy for managing tax, shipping and other standard conditions)
type: 'voucher',
target: 2, // cart item id
value: '-10%', // removes 10% of the value of item 2
},
{
name: 'Tax',
type: 'tax',
target: 'subtotal',
value: '10%', // adds 10% of subtotal to total
}
]);
// List cart conditions
await cart.conditions()
// Get condition
await cart.condition('Voucher 2')
// Remove condition
await cart.removeCondition('Voucher 2')
// Clear all cart conditions
await cart.clearConditions()
// Save currency. Returns `AUD`
let d1 = await cart.data('currency', 'AUD')
// Get saved data
let d2 = await cart.data('currency')
// Use dot notation
await cart.data('customer.name', 'Johnn Doe')
await cart.data('customer.email', '[email protected]')
await cart.data('customer') // returns { name: 'Johnn Doe', email: '[email protected]' }
await cart.data('token', '1233')
await cart.data() // returns { currency: 'AUD', customer: { name: 'Johnn Doe', email: '[email protected]' }, token: '1233' }
// Alternatively, set the above data by passing an object
// Note that this will NOT override `token` field set above
await cart.data({
currency: 'AUD',
customer: { name: 'Johnn Doe', email: '[email protected]' }
})
// If cart is empty
await cart.empty()
// Count item entries in cart
await cart.count()
Return the cart content.
// Get cart contents
await cart.content()
// List cart items
await cart.items()
// Get cart subtotal
await cart.subtotal()
// Get cart total
await cart.total()
await cart.clear()
// Do not clear conditions and data
await cart.clear({ conditions: false, data: false })
const cart2 = await cart.copy(new_session_id)
// Do not copy conditions and data. Also pass a new config
const cart3 = await cart.copy(new_session_id, { conditions: false, data: false }, new_config)
// Get the storage instance
const storage = cart.storage()
// Get theunderlying data loader
const loader = cart.loader()
Contribution Guidelines
Any pull requests or discussions are welcome. Note that every pull request providing new feature or correcting a bug should be created with appropriate unit tests.