react-shopping-cart
react-shopping-cart copied to clipboard
Powerful shopping cart
React shopping cart
Shopping cart package provides several components:
- Cart
- Product
- CheckoutButton
which can be used separately or in union. By default Redux is the framework to operate with data.
So, it's your choice to use Redux or not, but its reducers, actions and action types are already included.
Pay attention! All components are Pure.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Demo
Latest version demo (example1)
Usage
yarn add react-shopping-cart
npm i --save react-shopping-cart
Examples
In all cases you must include bootstrap version 4 (^alpha 0.6) in your project
import "bootstrap/dist/css/bootstrap.css";
And if you want to see animation, also include animate.css
import "animate.css/animate.min.css";
Also want some icons?
import "font-awesome/css/font-awesome.min.css";
With Redux. After store initialization you must dispatch setCartCurrency action or 'USD' will be used as cart's currency.
import React, { PureComponent } from "react";
import { Provider } from "react-redux";
import { createStore, combineReducers } from "redux";
import {
Cart,
Product,
CheckoutButton,
cartLocalization,
cartReducer,
setCartCurrency
} from "react-shopping-cart";
import "bootstrap/dist/css/bootstrap.css";
import "animate.css/animate.min.css";
import "font-awesome/css/font-awesome.min.css";
const { getDefaultLocalization } = cartLocalization;
// You may take localization object from wherever you want, that's just an example
// For more information, see localization section
const iPadCaseLocalization = {
color: "Color",
iPadCase: "iPad case",
red: "Red",
green: "Green",
yellow: "Yellow",
GBP: "£",
EUR: "€",
USD: "$"
};
const iPadPropertiesWithAdditionalCostLocalization = {
yellow: "Yellow (+{cost, number, CUR})"
};
const store = createStore(
combineReducers({
cart: cartReducer
// Your own reducers, sir
})
);
store.dispatch(setCartCurrency("USD"));
class App extends PureComponent {
state = {
product: {
name: "iPadCase",
id: "ipad-case",
path: "/shop/ipad-case/",
properties: {
color: [
"red",
"green",
{
additionalCost: {
GBP: 1,
EUR: 2,
USD: 3.5
},
value: "yellow"
}
]
},
propertiesToShowInCart: ["color"],
prices: { GBP: 70, EUR: 80, USD: 90 },
currency: "GBP",
imageSrc: "1-483x321.jpeg"
},
getProductLocalization: getDefaultLocalization("product", "en", {
...iPadCaseLocalization,
...iPadPropertiesWithAdditionalCostLocalization
}),
getCheckoutButtonLocalization: getDefaultLocalization(
"checkoutButton",
"en",
iPadCaseLocalization
),
getCartLocalization: getDefaultLocalization(
"cart",
"en",
iPadCaseLocalization
)
};
render() {
const {
product,
getCheckoutButtonLocalization,
getProductLocalization,
getCartLocalization
} = this.state;
const checkoutButtonElement = (
<CheckoutButton
getLocalization={getCheckoutButtonLocalization}
checkoutURL="/to/my/checkout"
/>
);
return (
<Provider store={store}>
<div className="container">
<Product
{...product}
checkoutButton={checkoutButtonElement}
getLocalization={getProductLocalization}
/>
<Cart
checkoutButton={checkoutButtonElement}
getLocalization={getCartLocalization}
/>
</div>
</Provider>
);
}
}
export default App;
// You may also import actions and actionTypes
import { cartActions, cartActionTypes } from "react-shopping-cart";
// And do some cool things with them
Without redux
import React, { PureComponent } from "react";
import {
CartComponent,
ProductComponent,
CheckoutButtonComponent,
cartLocalization
} from "react-shopping-cart";
import "bootstrap/dist/css/bootstrap.css";
import "animate.css/animate.min.css";
import "font-awesome/css/font-awesome.min.css";
const { getDefaultLocalization } = cartLocalization;
// You may take localization object from wherever you want, that's just an example
// For more information, see localization section
const iPadCaseLocalization = {
color: "Color",
iPadCase: "iPad case",
red: "Red",
green: "Green",
yellow: "Yellow",
GBP: "£",
EUR: "€",
USD: "$"
};
const iPadPropertiesWithAdditionalCostLocalization = {
yellow: "Yellow (+{cost, number, CUR})"
};
class App extends PureComponent {
state = {
products: {},
product: {
name: "iPadCase",
id: "ipad-case",
path: "/shop/ipad-case/",
properties: {
color: [
"red",
"green",
{
additionalCost: {
GBP: 1,
EUR: 2,
USD: 3.5
},
value: "yellow"
}
]
},
propertiesToShowInCart: ["color"],
prices: { GBP: 70, EUR: 80, USD: 90 },
currency: "GBP",
imageSrc: "1-483x321.jpeg"
},
getProductLocalization: getDefaultLocalization("product", "en", {
...iPadCaseLocalization,
...iPadPropertiesWithAdditionalCostLocalization
}),
getCheckoutButtonLocalization: getDefaultLocalization(
"checkoutButton",
"en",
iPadCaseLocalization
),
getCartLocalization: getDefaultLocalization(
"cart",
"en",
iPadCaseLocalization
)
};
addProduct = (key, product, currency) =>
void this.setState(
({
products: { [key]: cartProduct = { quantity: 0 }, ...restOfProducts }
}) => ({
products: {
...restOfProducts,
[key]: {
...product,
quantity: product.quantity + cartProduct.quantity
}
}
})
);
generateProductKey = (id, properties) =>
`${id}/${Object.entries(properties).join("_")}`;
updateProduct = (key, updatedProduct) => void console.log(":)");
removeProduct = key => void console.log(":C");
render() {
const {
addProduct,
generateProductKey,
updateProduct,
removeProduct,
state
} = this;
const {
getProductLocalization,
getCheckoutButtonLocalization,
getCartLocalization,
products,
product
} = state;
const checkoutButtonElement = (
<CheckoutButtonComponent
grandTotal={500}
hidden={false}
checkoutURL="/to/my/checkout"
currency="GBP"
getLocalization={getCheckoutButtonLocalization}
/>
);
return (
<div className="container">
<ProductComponent
{...product}
checkoutButton={checkoutButtonElement}
onAddProduct={
addProduct
// Help product to get into the cart
}
generateProductKey={
generateProductKey
// create product key as you wish
}
getLocalization={getProductLocalization}
/>
<CartComponent
products={
products
// Provide your own product's Object(Look at Products)
}
onUpdateProduct={
updateProduct
// Update something
}
getLocalization={getCartLocalization}
currency="GBP"
onRemoveProduct={
removeProduct
// Remove something
}
checkoutButton={checkoutButtonElement}
isCartEmpty={false}
getLocalization={getCartLocalization}
/>
</div>
);
}
}
export default App;
Localization
The default localization library is intl-messageformat. In order to localize your cart, you can chose one of the possible ways:
- Create your own getLocalization function and pass it as prop to the cart's components
- Create getLocalization function with bound localization using defaultLocalization object and getLocalization, getDefaultLocalization functions from cartLocalization module, pass it as prop to the cart's components
- Don't do anything and see only default language in your cart :C
Generally, components require a function, which takes id and params(optional) and returns string, based on received arguments.
The first one should look like that if you're also using intl-messageformat:
import React from 'react';
import IntlMessageFormat from 'intl-messageformat';
import { Cart } from 'react-shopping-cart';
const localization = {
en: {
cart : {
GBP: '£',
},
},
};
const getLocalization = (localizationPart, language, id, params = {}) =>
new IntlMessageFormat(localizationPart[id], language).format(params);
<Cart
getLocalization={(...args) => getLocalization(localization.en.cart, 'en', ...args)}
/>
Or you could use getDefaultLocalization function from cartLocalization:
import React from 'react';
import { Cart, cartLocalization } from 'react-shopping-cart';
const { getDefaultLocalization } = cartLocalization;
const localization = {
GBP: '£',
USD: '$',
};
<Cart
getLocalization={getDefaultLocalization('cart', 'en', localization)}
/>
Example usage of getLocalization function from cartLocalization:
import React from 'react';
import { Cart, cartLocalization } from 'react-shopping-cart';
const { getLocalization, defaultLocalization } = cartLocalization;
const localization = {
en: {
cart : {
GBP: '£',
},
},
};
const mergedEnCartLocalization = {
...localization.en.cart,
...defaultLocalization.en.cart,
};
<Cart
getLocalization={(...args) => getLocalization(mergedEnCartLocalization, 'en', ...args)}
/>
For built-in getLocalization function you may write your translation for default statements as a string or object in format { component : Function | string, text : string, props? : object }. Because all components are pure, in order to relocalize your components, you should pass new getLocalization function, not old with changed scope.
Localization default ids and params bindings:
-
cart:
-
no params
- shoppingCartTitle
-
{ quantity, price, total, currency, name, localizedName, localizedCurrency, }
- productName
- quantityLabel
- priceLabel
- priceValue
- totalLabel
- totalValue
- remove
- your currency
- your product's name
-
{name, value, localizedName, localizedValue,}
- productPropertyLabel
- productPropertyValue
- your product's property name
- your product's property value (if string of course)
-
-
checkoutButton
- {currency, total, localizedCurrency,}
- checkoutTotal
- your currency
- {currency, total, localizedCurrency,}
-
product
- {
name,
quantity,
price,
currency,
localizedName,
localizedCurrency,
}
- price
- quantityLabel
- propertyLabel
- addToCart
- your product's name
- your product's currency
- {
name,
currency,
localizedName,
localizedCurrency,
}
- your product's name
- your product's property name
- {(optional) cost}
- your product's property value (if string of course)
- {
name,
quantity,
price,
currency,
localizedName,
localizedCurrency,
}
Table of Contents
- Cart
- Props
- Properties
- Props
- CartProduct
- ProductPropertyLabel
- CheckoutButton
- Props
- Properties
- Props
- helpers
- configure
- Parameters
- isNaturalNumber
- Parameters
- parseInteger
- Parameters
- isObject
- Parameters
- getAbsoluteOffsetTop
- Parameters
- DefaultLinkComponent
- Parameters
- fixInputValueStartingWithZero
- Parameters
- scrollFunction
- Parameters
- configure
- Product
- Props
- Properties
- Props
- ProductPropertiesOptions
- ScrollPosition
- ScrollFunction
- ProductPropertyInput
- OptionIndex
- OptionObject
- PropertyOption
- PropertyOptions
- OnChange
- ProductPropertyOption
- ProductProperties
- Prices
- ProductData
- Properties
- Examples
- Products
- GenerateProductKey
- AddProduct
- UpdateProduct
- RemoveProduct
- GetLocalization
- CartAddAction
- Properties
- CartUpdateAction
- Properties
- CartRemoveAction
- Properties
- CartEmptyAction
- Properties
- CartSetCurrencyAction
- Properties
- CartAction
- LocalizationPattern
- Localization
- MultiLocalization
- CartState
- Properties
- DefaultLinkComponentProps
- Properties
- Link$Component
Cart
Extends React.PureComponent
Component which represents shopping cart.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Props
Type: Object
Properties
productsProducts Products map. Required.currencystring Current currency. Required.isCartEmptyboolean Display cart or not. Required.onUpdateProductUpdateProduct Function which will be called when product should be updated. First arg is product's key in products map, second - updated product. Required.onRemoveProductRemoveProduct Function to call when product should be removed from cart. One argument - product's key. Required.getLocalizationGetLocalization Required.hideHeaderboolean? Hide cart's header. Default is false.checkoutButtonReactElement? Button to display in the bottom of cart. Default is null.iconTrashClassNamestring? ClassName for trash icon on remove button. Default is 'fa fa-trash mx-1'.altProductImageSrcstring? Alt image src for products. Default is ''.cartCSSTransitionObject? Cart's config for react-transition-group/CSSTransition. Look at src/components/Cart/Cart.js for details.cartItemCSSTransitionObject? Cart item's config for react-transition-group/CSSTransition. Look at src/components/Cart/Cart.js for details.linkComponentLink$Component? React Component, will receive propto="%your product's page%". I'd recommend you to take a look at react-router's Link.
CartProduct
Extends React.PureComponent
React component to display product in cart.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
ProductPropertyLabel
Extends React.PureComponent
React component to display product's property value in cart.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
CheckoutButton
Extends React.PureComponent
Checkout button with grand total.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Props
Type: Object
Properties
grandTotalnumber Required.currencystring Current currency. Required.hiddenboolean Show or hide button. Required.checkoutURLstring Link to checkout page. Required.getLocalizationGetLocalization Required.iconCheckoutClassNamestring? ClassName for cart icon on checkout button. Default is 'fa fa-shopping-cart mx-1'.buttonCSSTransitionObject? Transition's config for react-transition-group/CSSTransition.linkComponentLink$Component? React Component, will receive propto="%your product's page%". I'd recommend you to take a look at react-router's Link.
helpers
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
configure
Parameters
ComponentReact$ComponentType<Props>configurationObject
Returns React$ComponentType<Props>
isNaturalNumber
Parameters
numnumber
Returns boolean
parseInteger
Parameters
numstring
Returns number
isObject
Parameters
valueany
Returns boolean
getAbsoluteOffsetTop
Parameters
$0HTMLElement (optional, default{})$0.offsetTop$0.offsetParent
Returns number
DefaultLinkComponent
Parameters
$0DefaultLinkComponentProps$0.to$0.otherProps...any
Returns React$Element<any>
fixInputValueStartingWithZero
Parameters
targetHTMLInputElementquantitynumber
scrollFunction
Parameters
targetEventTargetscrollPosition(number | function (currentTarget: Element): number)scrollAnimationConfigObject
Product
Extends React.PureComponent
React component - Product form with price.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Props
Type: Object
Properties
idstring Product's id. Required.namestring Name to display pattern. Required.pathstring Path to product. Required.pricesPrices {currency: value}. RequiredimageSrcstring Path to main image. Required.currencystring Current price currency. Required.onAddProductAddProduct Function to call when user wants to add product in his cart. Required.generateProductKeyGenerateProductKey Required.getLocalizationGetLocalization Required.propertiesProductPropertiesOptions? Custom product properties. Each property option list consists of number, string or shape({ additionalCost(optional), onSelect(optional), value(required)})propertiesToShowInCartArray<string>? Array of propery names to display in cart.scrollAnimationConfigObject? Config for animateScroll (from react-scroll) scrollTo function.scrollPositionScrollPosition? Position to scroll after product add. May be number or function returning number.scrollFunctionScrollFunction? Function which will be called when product has been added.iconAddProductClassNamestring? ClassName for cart icon on add to button. Default is 'fa fa-cart-plus mx-1'.checkoutButtonReactElement?descriptionNodeReactNode? Node to display before price element.afterPriceNodeReactNode? Node to display after price element.
ProductPropertiesOptions
Type: Object<string, PropertyOptions>
ScrollPosition
Type: (number | function (currentTarget: Element): number)
ScrollFunction
Type: function (currentTarget: EventTarget, scrollPosition: (number | function (currentTarget: Element): number), scrollAnimationConfig: Object): void
ProductPropertyInput
Extends React.PureComponent
React form for product property(options select only).
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
OptionIndex
OptionObject
Type: Object
PropertyOption
Type: (ProductPropertyOption | OptionObject)
PropertyOptions
Type: Array<PropertyOption>
OnChange
Type: function (obj: {value: OptionIndex}): void
Shopping cart's data types
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
ProductPropertyOption
ProductProperties
Type: Object<string, (string | number)>
Prices
ProductData
Properties
idstringquantitynumberpropertiesProductPropertiesnamestringpricesPricesimageSrcstringpathstringpropertiesToShowInCartArray<string>
Examples
{
id: 'macbook-case',
quantity: 3,
properties: {
color: 'red'
},
name: 'macbookCase',
prices: {
GBP: 50
},
path: '/shop/macbook-case/',
imageSrc: '/shop/macbook-case/1-483x321.jpeg',
propertiesToShowInCart: ['color']
}
Products
Type: Object<string, ProductData>
GenerateProductKey
Type: function (id: string, properties: ProductProperties): string
AddProduct
Type: function (key: string, product: ProductData, currency: string): void
UpdateProduct
Type: function (key: string, updatedProduct: ProductData): void
RemoveProduct
Type: function (key: string): void
GetLocalization
Type: function (id: string, params: Object): (string | React$Element<any>)
CartAddAction
Properties
CartUpdateAction
Properties
type"cart/UPDATE"keystringupdatedProductProductData
CartRemoveAction
Properties
type"cart/REMOVE"keystring
CartEmptyAction
Properties
type"cart/EMPTY"
CartSetCurrencyAction
Properties
type"cart/SET_CURRENCY"currencystring
CartAction
Type: (CartAddAction | CartUpdateAction | CartRemoveAction | CartEmptyAction | CartSetCurrencyAction)
LocalizationPattern
Type: (string | {component: (string | React$ComponentType<any>), props: Object?, text: string})
Localization
Type: Object<string, LocalizationPattern>
MultiLocalization
Type: Object<string, Object<string, Localization>>
CartState
Properties
cart{currency: string, products: Products}
DefaultLinkComponentProps
Properties
tostring
Link$Component
Type: function (DefaultLinkComponentProps): React$Element<any>
Development
Developer mode
Run webpack-dev-server for example1
yarn start
npm run start
Build
yarn build
npm run build
And then check dist folder
Build Example
yarn build_example
npm run build_example
And then check examples folder
Testing
Jest is used for tests
yarn test
npm run test
Linter
ESLint is used as a linter
yarn lint
npm run lint
Formatter
prettier-eslint is used as a formatter
yarn fmt
npm run fmt
Flow Type
Check types in project using Flow
yarn flow
npm run flow
Autodoc
Generate doc using documentation js
yarn doc
npm run doc
And then look at README.md