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
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:
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
product
Extends React.PureComponent
Component which represents shopping cart.
Meta
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 prop to="%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
Extends React.PureComponent
React component to display product's property value in cart.
Meta
Extends React.PureComponent
Checkout button with grand total.
Meta
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 prop to="%your product's page%"
.
I'd recommend you to take a look at react-router's Link.Meta
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
HTMLInputElement quantity
number target
EventTarget scrollPosition
(number | function (currentTarget: Element): number) scrollAnimationConfig
Object Extends React.PureComponent
React component - Product form with price.
Meta
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
Type: Object
Type: (ProductPropertyOption | OptionObject)
Type: Array<PropertyOption>
Type: function (obj: {value: OptionIndex}): void
Shopping cart's data types
Meta
Type: Object<string, (string | number)>
id
string quantity
number properties
ProductProperties name
string prices
Prices imageSrc
string path
string propertiesToShowInCart
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
string product
ProductData productCurrency
string type
"cart/UPDATE"
key
string updatedProduct
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