Shopping cart package provides several components:
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
Latest version demo (example1)
Usage
yarn add react-shopping-cartnpm i --save react-shopping-cartExamples
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 themWithout 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;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,
}
- Cart
- CartProduct
- ProductPropertyLabel
- CheckoutButton
- helpers
- Product
- ProductPropertiesOptions
- ScrollPosition
- ScrollFunction
- ProductPropertyInput
- OptionIndex
- OptionObject
- PropertyOption
- PropertyOptions
- OnChange
- ProductPropertyOption
- ProductProperties
- Prices
- ProductData
- Products
- GenerateProductKey
- AddProduct
- UpdateProduct
- RemoveProduct
- GetLocalization
- CartAddAction
- CartUpdateAction
- CartRemoveAction
- CartEmptyAction
- CartSetCurrencyAction
- CartAction
- LocalizationPattern
- Localization
- MultiLocalization
- CartState
- DefaultLinkComponentProps
- Link$Component
Extends React.PureComponent
Component which represents shopping cart.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Type: Object
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.
Extends React.PureComponent
React component to display product in cart.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Extends React.PureComponent
React component to display product's property value in cart.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Extends React.PureComponent
Checkout button with grand total.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Type: Object
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.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
ComponentReact$ComponentType<Props>configurationObject
Returns React$ComponentType<Props>
numnumber
Returns boolean
numstring
Returns number
valueany
Returns boolean
$0HTMLElement (optional, default{})$0.offsetTop$0.offsetParent
Returns number
$0DefaultLinkComponentProps$0.to$0.otherProps...any
Returns React$Element<any>
targetHTMLInputElementquantitynumber
targetEventTargetscrollPosition(number | function (currentTarget: Element): number)scrollAnimationConfigObject
Extends React.PureComponent
React component - Product form with price.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Type: Object
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.
Type: Object<string, PropertyOptions>
Type: (number | function (currentTarget: Element): number)
Type: function (currentTarget: EventTarget, scrollPosition: (number | function (currentTarget: Element): number), scrollAnimationConfig: Object): void
Extends React.PureComponent
React form for product property(options select only).
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Type: Object
Type: (ProductPropertyOption | OptionObject)
Type: Array<PropertyOption>
Type: function (obj: {value: OptionIndex}): void
Shopping cart's data types
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Type: Object<string, (string | number)>
idstringquantitynumberpropertiesProductPropertiesnamestringpricesPricesimageSrcstringpathstringpropertiesToShowInCartArray<string>
{
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']
}Type: Object<string, ProductData>
Type: function (id: string, properties: ProductProperties): string
Type: function (key: string, product: ProductData, currency: string): void
Type: function (key: string, updatedProduct: ProductData): void
Type: function (key: string): void
Type: function (id: string, params: Object): (string | React$Element<any>)
type"cart/ADD"keystringproductProductDataproductCurrencystring
type"cart/UPDATE"keystringupdatedProductProductData
type"cart/REMOVE"keystring
type"cart/EMPTY"
type"cart/SET_CURRENCY"currencystring
Type: (CartAddAction | CartUpdateAction | CartRemoveAction | CartEmptyAction | CartSetCurrencyAction)
Type: (string | {component: (string | React$ComponentType<any>), props: Object?, text: string})
Type: Object<string, LocalizationPattern>
Type: Object<string, Object<string, Localization>>
tostring
Type: function (DefaultLinkComponentProps): React$Element<any>
Developer mode
Run webpack-dev-server for example1
yarn startnpm run startBuild
yarn buildnpm run buildAnd then check dist folder
Build Example
yarn build_examplenpm run build_exampleAnd then check examples folder
Testing
Jest is used for tests
yarn testnpm run testLinter
ESLint is used as a linter
yarn lintnpm run lintFormatter
prettier-eslint is used as a formatter
yarn fmtnpm run fmtFlow Type
Check types in project using Flow
yarn flownpm run flowAutodoc
Generate doc using documentation js
yarn docnpm run docAnd then look at README.md