diff --git a/ecommerce/views/v0/__init__.py b/ecommerce/views/v0/__init__.py
index f41fa312e2..35c691fa53 100644
--- a/ecommerce/views/v0/__init__.py
+++ b/ecommerce/views/v0/__init__.py
@@ -559,6 +559,17 @@ def cart(self, request):
return Response(BasketWithProductSerializer(basket).data)
+ @action(
+ detail=False,
+ methods=["get"],
+ name="Basket Items Count",
+ url_name="basket_items_count",
+ )
+ def basket_items_count(self, request):
+ basket, _ = Basket.objects.get_or_create(user=request.user)
+
+ return Response(basket.basket_items.count())
+
@method_decorator(csrf_exempt, name="dispatch")
class CheckoutCallbackView(View):
diff --git a/frontend/public/src/components/Header.js b/frontend/public/src/components/Header.js
index 4d763ef38a..2181d0cda8 100644
--- a/frontend/public/src/components/Header.js
+++ b/frontend/public/src/components/Header.js
@@ -10,10 +10,11 @@ import TopBar from "./TopBar"
type Props = {
currentUser: CurrentUser,
+ cartItemsCount: number,
location: ?Location
}
-const Header = ({ currentUser, location }: Props) => {
+const Header = ({ currentUser, cartItemsCount, location }: Props) => {
if (currentUser && currentUser.is_authenticated) {
Sentry.getCurrentScope().setUser({
id: currentUser.id,
@@ -30,7 +31,11 @@ const Header = ({ currentUser, location }: Props) => {
}
return (
-
+
)
}
diff --git a/frontend/public/src/components/TopBar.js b/frontend/public/src/components/TopBar.js
index fe6990ca59..71eb585f3f 100644
--- a/frontend/public/src/components/TopBar.js
+++ b/frontend/public/src/components/TopBar.js
@@ -14,10 +14,11 @@ import { checkFeatureFlag } from "../lib/util"
type Props = {
currentUser: CurrentUser,
+ cartItemsCount: number,
location: ?Location
}
-const TopBar = ({ currentUser }: Props) => {
+const TopBar = ({ currentUser, cartItemsCount }: Props) => {
// Delay any alert displayed on page-load by 500ms in order to
// ensure the alert is read by screen readers.
const [showComponent, setShowComponent] = useState(false)
@@ -35,7 +36,6 @@ const TopBar = ({ currentUser }: Props) => {
currentUser.id :
"anonymousUser"
)
- const cartItemCount = 0
return (
{showComponent ? (
@@ -80,9 +80,9 @@ const TopBar = ({ currentUser }: Props) => {
onClick={() => (window.location = routes.cart)}
aria-label="Cart"
/>
- {cartItemCount ? (
+ {cartItemsCount ? (
- {cartItemCount}
+ {cartItemsCount}
) : null}
{
describe("for anonymous users", () => {
const user = makeAnonymousUser()
+ const cartItemsCount = 0
it("has an AnonymousMenu component", () => {
assert.isOk(
- shallow()
+ shallow(
+
+ )
.find("AnonymousMenu")
.exists()
)
@@ -21,9 +28,16 @@ describe("TopBar component", () => {
describe("for logged in users", () => {
const user = makeUser()
+ const cartItemsCount = 3
it("has a UserMenu component", () => {
assert.isOk(
- shallow()
+ shallow(
+
+ )
.find("UserMenu")
.exists()
)
diff --git a/frontend/public/src/containers/App.js b/frontend/public/src/containers/App.js
index 1b5496df62..0189997d6a 100644
--- a/frontend/public/src/containers/App.js
+++ b/frontend/public/src/containers/App.js
@@ -32,11 +32,16 @@ import CatalogPage from "./pages/CatalogPage"
import type { Match, Location } from "react-router"
import type { CurrentUser } from "../flow/authTypes"
+import {
+ cartItemsCountQuery,
+ cartItemsCountSelector
+} from "../lib/queries/cart"
type Props = {
match: Match,
location: Location,
currentUser: ?CurrentUser,
+ cartItemsCount: number,
addUserNotification: Function
}
@@ -59,7 +64,7 @@ export class App extends React.Component {
}
render() {
- const { match, currentUser, location } = this.props
+ const { match, currentUser, cartItemsCount, location } = this.props
if (!currentUser) {
// application is still loading
return
@@ -67,7 +72,11 @@ export class App extends React.Component {
return (
-
+
{
}
const mapStateToProps = createStructuredSelector({
- currentUser: currentUserSelector
+ currentUser: currentUserSelector,
+ cartItemsCount: cartItemsCountSelector
})
const mapDispatchToProps = {
addUserNotification
}
-const mapPropsToConfig = () => [users.currentUserQuery()]
-
+const mapPropsToConfig = () => [cartItemsCountQuery(), users.currentUserQuery()]
export default compose(
connect(mapStateToProps, mapDispatchToProps),
connectRequest(mapPropsToConfig)
diff --git a/frontend/public/src/containers/HeaderApp.js b/frontend/public/src/containers/HeaderApp.js
index fc3fb44be1..7a3256503a 100644
--- a/frontend/public/src/containers/HeaderApp.js
+++ b/frontend/public/src/containers/HeaderApp.js
@@ -15,9 +15,14 @@ import {
import type { Store } from "redux"
import type { CurrentUser } from "../flow/authTypes"
+import {
+ cartItemsCountQuery,
+ cartItemsCountSelector
+} from "../lib/queries/cart"
type Props = {
currentUser: ?CurrentUser,
+ cartItemsCount: number,
store: Store<*, *>,
addUserNotification: Function
}
@@ -41,22 +46,29 @@ export class HeaderApp extends React.Component {
}
render() {
- const { currentUser } = this.props
+ const { currentUser, cartItemsCount } = this.props
if (!currentUser) {
// application is still loading
return
}
- return
+ return (
+
+ )
}
}
const mapStateToProps = createStructuredSelector({
- currentUser: currentUserSelector
+ currentUser: currentUserSelector,
+ cartItemsCount: cartItemsCountSelector
})
-const mapPropsToConfig = () => [users.currentUserQuery()]
+const mapPropsToConfig = () => [cartItemsCountQuery(), users.currentUserQuery()]
const mapDispatchToProps = {
addUserNotification
diff --git a/frontend/public/src/lib/queries/cart.js b/frontend/public/src/lib/queries/cart.js
index 2cf56a0b18..eb5c75c224 100644
--- a/frontend/public/src/lib/queries/cart.js
+++ b/frontend/public/src/lib/queries/cart.js
@@ -5,6 +5,10 @@ import { getCsrfOptions, nextState } from "./util"
export const cartSelector = pathOr(null, ["entities", "cartItems"])
export const totalPriceSelector = pathOr(null, ["entities", "totalPrice"])
export const orderHistorySelector = pathOr(null, ["entities", "orderHistory"])
+export const cartItemsCountSelector = pathOr(null, [
+ "entities",
+ "cartItemsCount"
+])
export const discountedPriceSelector = pathOr(null, [
"entities",
@@ -115,3 +119,14 @@ export const applyCartMutation = (productId: string) => ({
},
update: {}
})
+
+export const cartItemsCountQuery = () => ({
+ queryKey: "cartItemsCount",
+ url: `/api/checkout/basket_items_count/`,
+ transform: json => ({
+ cartItemsCount: json
+ }),
+ update: {
+ cartItemsCount: nextState
+ }
+})