Skip to content

Commit 8a78d9f

Browse files
Part 3 : Cart Page added
1 parent e6a4c46 commit 8a78d9f

File tree

6 files changed

+229
-21
lines changed

6 files changed

+229
-21
lines changed

src/App.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
Route,
1111
Link,
1212
} from 'react-router-dom';
13+
import Cart from './features/cart/Cart';
14+
import CartPage from './pages/CartPage';
1315

1416
const router = createBrowserRouter([
1517
{
@@ -24,6 +26,10 @@ const router = createBrowserRouter([
2426
path: '/signup',
2527
element: <SignupPage></SignupPage>,
2628
},
29+
{ // only for testing - then page will be added
30+
path: '/cart',
31+
element: <CartPage></CartPage>,
32+
},
2733
]);
2834

2935
function App() {

src/features/cart/Cart.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import React, { useState, Fragment } from 'react';
2+
import { useSelector, useDispatch } from 'react-redux';
3+
import { increment, incrementAsync, selectCount } from './cartSlice';
4+
import { Dialog, Transition } from '@headlessui/react';
5+
import { XMarkIcon } from '@heroicons/react/24/outline';
6+
import { Link } from 'react-router-dom';
7+
8+
const products = [
9+
{
10+
id: 1,
11+
name: 'Throwback Hip Bag',
12+
href: '#',
13+
color: 'Salmon',
14+
price: '$90.00',
15+
quantity: 1,
16+
imageSrc:
17+
'https://tailwindui.com/img/ecommerce-images/shopping-cart-page-04-product-01.jpg',
18+
imageAlt:
19+
'Salmon orange fabric pouch with match zipper, gray zipper pull, and adjustable hip belt.',
20+
},
21+
{
22+
id: 2,
23+
name: 'Medium Stuff Satchel',
24+
href: '#',
25+
color: 'Blue',
26+
price: '$32.00',
27+
quantity: 1,
28+
imageSrc:
29+
'https://tailwindui.com/img/ecommerce-images/shopping-cart-page-04-product-02.jpg',
30+
imageAlt:
31+
'Front of satchel with blue canvas body, black straps and handle, drawstring top, and front zipper pouch.',
32+
},
33+
// More products...
34+
];
35+
36+
export default function Cart() {
37+
const count = useSelector(selectCount);
38+
const dispatch = useDispatch();
39+
const [open, setOpen] = useState(true);
40+
41+
return (
42+
<>
43+
<div>
44+
<div className="mx-auto mt-12 bg-white max-w-7xl px-4 sm:px-6 lg:px-8">
45+
<div className="border-t border-gray-200 px-4 py-6 sm:px-6">
46+
<h1 className="text-4xl my-5 font-bold tracking-tight text-gray-900">
47+
Cart
48+
</h1>
49+
<div className="flow-root">
50+
<ul role="list" className="-my-6 divide-y divide-gray-200">
51+
{products.map((product) => (
52+
<li key={product.id} className="flex py-6">
53+
<div className="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200">
54+
<img
55+
src={product.imageSrc}
56+
alt={product.imageAlt}
57+
className="h-full w-full object-cover object-center"
58+
/>
59+
</div>
60+
61+
<div className="ml-4 flex flex-1 flex-col">
62+
<div>
63+
<div className="flex justify-between text-base font-medium text-gray-900">
64+
<h3>
65+
<a href={product.href}>{product.name}</a>
66+
</h3>
67+
<p className="ml-4">{product.price}</p>
68+
</div>
69+
<p className="mt-1 text-sm text-gray-500">
70+
{product.color}
71+
</p>
72+
</div>
73+
<div className="flex flex-1 items-end justify-between text-sm">
74+
<div className="text-gray-500">
75+
<label
76+
htmlFor="quantity"
77+
className="inline mr-5 text-sm font-medium leading-6 text-gray-900"
78+
>
79+
Qty
80+
</label>
81+
<select>
82+
<option value="1">1</option>
83+
<option value="2">2</option>
84+
</select>
85+
</div>
86+
87+
<div className="flex">
88+
<button
89+
type="button"
90+
className="font-medium text-indigo-600 hover:text-indigo-500"
91+
>
92+
Remove
93+
</button>
94+
</div>
95+
</div>
96+
</div>
97+
</li>
98+
))}
99+
</ul>
100+
</div>
101+
</div>
102+
103+
<div className="border-t border-gray-200 px-4 py-6 sm:px-6">
104+
<div className="flex justify-between text-base font-medium text-gray-900">
105+
<p>Subtotal</p>
106+
<p>$262.00</p>
107+
</div>
108+
<p className="mt-0.5 text-sm text-gray-500">
109+
Shipping and taxes calculated at checkout.
110+
</p>
111+
<div className="mt-6">
112+
<a
113+
href="#"
114+
className="flex items-center justify-center rounded-md border border-transparent bg-indigo-600 px-6 py-3 text-base font-medium text-white shadow-sm hover:bg-indigo-700"
115+
>
116+
Checkout
117+
</a>
118+
</div>
119+
<div className="mt-6 flex justify-center text-center text-sm text-gray-500">
120+
<p>
121+
or
122+
<Link to="/">
123+
<button
124+
type="button"
125+
className="font-medium text-indigo-600 hover:text-indigo-500"
126+
onClick={() => setOpen(false)}
127+
>
128+
Continue Shopping
129+
<span aria-hidden="true"> &rarr;</span>
130+
</button>
131+
</Link>
132+
</p>
133+
</div>
134+
</div>
135+
</div>
136+
</div>
137+
</>
138+
);
139+
}

src/features/cart/cartAPI.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function fetchCount(amount = 1) {
2+
return new Promise(async (resolve) =>{
3+
const response = await fetch('http://localhost:8080')
4+
const data = await response.json()
5+
resolve({data})
6+
}
7+
);
8+
}

src/features/cart/cartSlice.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
2+
import { fetchCount } from './cartAPI';
3+
4+
const initialState = {
5+
value: 0,
6+
status: 'idle',
7+
};
8+
9+
export const incrementAsync = createAsyncThunk(
10+
'counter/fetchCount',
11+
async (amount) => {
12+
const response = await fetchCount(amount);
13+
// The value we return becomes the `fulfilled` action payload
14+
return response.data;
15+
}
16+
);
17+
18+
export const counterSlice = createSlice({
19+
name: 'counter',
20+
initialState,
21+
reducers: {
22+
increment: (state) => {
23+
state.value += 1;
24+
},
25+
},
26+
extraReducers: (builder) => {
27+
builder
28+
.addCase(incrementAsync.pending, (state) => {
29+
state.status = 'loading';
30+
})
31+
.addCase(incrementAsync.fulfilled, (state, action) => {
32+
state.status = 'idle';
33+
state.value += action.payload;
34+
});
35+
},
36+
});
37+
38+
export const { increment } = counterSlice.actions;
39+
40+
export const selectCount = (state) => state.counter.value;
41+
42+
export default counterSlice.reducer;

src/features/navbar/Navbar.js

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ShoppingCartIcon,
66
XMarkIcon,
77
} from '@heroicons/react/24/outline';
8+
import { Link } from 'react-router-dom';
89

910
const user = {
1011
name: 'Tom Cook',
@@ -65,16 +66,18 @@ function NavBar({ children }) {
6566
</div>
6667
<div className="hidden md:block">
6768
<div className="ml-4 flex items-center md:ml-6">
68-
<button
69-
type="button"
70-
className="rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
71-
>
72-
<span className="sr-only">View notifications</span>
73-
<ShoppingCartIcon
74-
className="h-6 w-6"
75-
aria-hidden="true"
76-
/>
77-
</button>
69+
<Link to="/cart">
70+
<button
71+
type="button"
72+
className="rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
73+
>
74+
<span className="sr-only">View notifications</span>
75+
<ShoppingCartIcon
76+
className="h-6 w-6"
77+
aria-hidden="true"
78+
/>
79+
</button>
80+
</Link>
7881
<span className="inline-flex items-center rounded-md mb-7 -ml-3 bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/10">
7982
3
8083
</span>
@@ -177,18 +180,19 @@ function NavBar({ children }) {
177180
{user.email}
178181
</div>
179182
</div>
180-
<button
181-
type="button"
182-
className="ml-auto flex-shrink-0 rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
183-
>
184-
<ShoppingCartIcon
185-
className="h-6 w-6"
186-
aria-hidden="true"
187-
/>
188-
189-
</button>
183+
<Link to="/cart">
184+
<button
185+
type="button"
186+
className="ml-auto flex-shrink-0 rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
187+
>
188+
<ShoppingCartIcon
189+
className="h-6 w-6"
190+
aria-hidden="true"
191+
/>
192+
</button>
193+
</Link>
190194
<span className="inline-flex items-center rounded-md bg-red-50 mb-7 -ml-3 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/10">
191-
3
195+
3
192196
</span>
193197
</div>
194198
<div className="mt-3 space-y-1 px-2">

src/pages/CartPage.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Cart from "../features/cart/Cart";
2+
3+
function CartPage() {
4+
return <div>
5+
<Cart></Cart>
6+
</div>;
7+
}
8+
9+
export default CartPage;

0 commit comments

Comments
 (0)