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-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;
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
products
Products Products map. Required.currency
string Current currency. Required.isCartEmpty
boolean Display cart or not. Required.onUpdateProduct
UpdateProduct Function which will be called when product should be updated. First arg is product's key in products map, second - updated product. Required.onRemoveProduct
RemoveProduct Function to call when product should be removed from cart. One argument - product's key. Required.getLocalization
GetLocalization Required.hideHeader
boolean? Hide cart's header. Default is false.checkoutButton
ReactElement? Button to display in the bottom of cart. Default is null.iconTrashClassName
string? ClassName for trash icon on remove button. Default is 'fa fa-trash mx-1'.altProductImageSrc
string? Alt image src for products. Default is ''.cartCSSTransition
Object? Cart's config for react-transition-group/CSSTransition. Look at src/components/Cart/Cart.js for details.cartItemCSSTransition
Object? Cart item's config for react-transition-group/CSSTransition. Look at src/components/Cart/Cart.js for details.linkComponent
Link$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
grandTotal
number Required.currency
string Current currency. Required.hidden
boolean Show or hide button. Required.checkoutURL
string Link to checkout page. Required.getLocalization
GetLocalization Required.iconCheckoutClassName
string? ClassName for cart icon on checkout button. Default is 'fa fa-shopping-cart mx-1'.buttonCSSTransition
Object? Transition's config for react-transition-group/CSSTransition.linkComponent
Link$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
Component
React$ComponentType<Props>configuration
Object
Returns React$ComponentType<Props>
num
number
Returns boolean
num
string
Returns number
value
any
Returns boolean
$0
HTMLElement (optional, default{}
)$0.offsetTop
$0.offsetParent
Returns number
$0
DefaultLinkComponentProps$0.to
$0.otherProps
...any
Returns React$Element<any>
target
HTMLInputElementquantity
number
target
EventTargetscrollPosition
(number | function (currentTarget: Element): number)scrollAnimationConfig
Object
Extends React.PureComponent
React component - Product form with price.
Meta
- author: Oleg Nosov <[email protected]>
- license: MIT
Type: Object
id
string Product's id. Required.name
string Name to display pattern. Required.path
string Path to product. Required.prices
Prices {currency: value}. RequiredimageSrc
string Path to main image. Required.currency
string Current price currency. Required.onAddProduct
AddProduct Function to call when user wants to add product in his cart. Required.generateProductKey
GenerateProductKey Required.getLocalization
GetLocalization Required.properties
ProductPropertiesOptions? Custom product properties. Each property option list consists of number, string or shape({ additionalCost(optional), onSelect(optional), value(required)})propertiesToShowInCart
Array<string>? Array of propery names to display in cart.scrollAnimationConfig
Object? Config for animateScroll (from react-scroll) scrollTo function.scrollPosition
ScrollPosition? Position to scroll after product add. May be number or function returning number.scrollFunction
ScrollFunction? Function which will be called when product has been added.iconAddProductClassName
string? ClassName for cart icon on add to button. Default is 'fa fa-cart-plus mx-1'.checkoutButton
ReactElement?descriptionNode
ReactNode? Node to display before price element.afterPriceNode
ReactNode? 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)>
id
stringquantity
numberproperties
ProductPropertiesname
stringprices
PricesimageSrc
stringpath
stringpropertiesToShowInCart
Array<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"
key
stringproduct
ProductDataproductCurrency
string
type
"cart/UPDATE"
key
stringupdatedProduct
ProductData
type
"cart/REMOVE"
key
string
type
"cart/EMPTY"
type
"cart/SET_CURRENCY"
currency
string
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>>
to
string
Type: function (DefaultLinkComponentProps): React$Element<any>
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