Skip to content

Commit 436387e

Browse files
authored
Merge pull request #18 from oslabs-beta/client
client is clienting
2 parents 000e18d + 34e10fd commit 436387e

File tree

12 files changed

+258
-4
lines changed

12 files changed

+258
-4
lines changed

examples_new/microservices/client/src/App.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Home from './pages/Home';
44
import Protected from './pages/Protected';
55
import SharedLayout from './pages/SharedLayout';
66
import NotFound from './pages/NotFound';
7+
import MyStore from './pages/MyStore';
8+
import BuyItem from './components/BuyItem';
79

810
function App() {
911
return (
@@ -18,6 +20,8 @@ function App() {
1820
}
1921
>
2022
<Route index element={<Home />} />
23+
<Route path='/:itemId' element={<BuyItem />} />
24+
<Route path="/my-store" element={<MyStore />} />
2125
</Route>
2226
<Route path="*" element={<NotFound />} />
2327
</Routes>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { useEffect, useState } from 'react';
2+
import { nanoid } from 'nanoid';
3+
import { useParams } from 'react-router-dom';
4+
import { useAppContext } from '../context/appContext';
5+
import { ItemDetails } from '../util/types';
6+
7+
const BuyItem = () => {
8+
const [item, setItem] = useState<ItemDetails | null>(null);
9+
const [amount, setAmount] = useState(1);
10+
const { getItemInventory } = useAppContext();
11+
const { itemId } = useParams();
12+
console.log(itemId);
13+
console.log(item);
14+
15+
useEffect(() => {
16+
const itemData = getItemInventory(itemId);
17+
setItem(itemData);
18+
// eslint-disable-next-line
19+
}, [item]);
20+
21+
// TODO replace with real inventory number
22+
const inventory = 20;
23+
console.log('Amount', amount);
24+
25+
const buildSelect = () => {
26+
const options = [];
27+
for (let i = 1; i <= inventory; i++) {
28+
options.push(
29+
<option key={nanoid()} value={i}>
30+
{i}
31+
</option>
32+
);
33+
}
34+
return options;
35+
};
36+
37+
return (
38+
<div>
39+
<select
40+
className="bg-light text-dark p-1 rounded-md w-full text-center mt-4"
41+
value={amount}
42+
onChange={e => setAmount(+e.target.value)}
43+
name="amount-select"
44+
>
45+
{buildSelect()}
46+
</select>
47+
</div>
48+
);
49+
};
50+
51+
export default BuyItem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Link, useLocation } from 'react-router-dom';
2+
import { AiFillHome } from 'react-icons/ai';
3+
import { FiMenu } from 'react-icons/fi';
4+
import { useState } from 'react';
5+
import { useAppContext } from '../context/appContext';
6+
7+
const Header = () => {
8+
const [showMenu, setShowMenu] = useState(false);
9+
const { pathname } = useLocation();
10+
const { logoutUser } = useAppContext();
11+
12+
return (
13+
<div className="fixed top-0 left-0 w-full flex justify-between items-center px-4 py-2">
14+
<Link
15+
to="/"
16+
className={`rounded-full p-2 text-2xl border-2
17+
${pathname === '/' ? 'border-light' : 'bg-light text-dark shadow-insetLight border-dark'}`}
18+
>
19+
<AiFillHome />
20+
</Link>
21+
<div>
22+
<div
23+
className={`text-2xl rounded-sm ${
24+
showMenu ? 'bg-light text-dark border-2 border-light' : ''
25+
}`}
26+
onClick={() => setShowMenu(!showMenu)}
27+
>
28+
<FiMenu />
29+
</div>
30+
{showMenu && (
31+
<div
32+
className="bg-white/40 rounded-md p-6 absolute top-14 right-4
33+
flex flex-col justify-center items-center text-center min-w-[150px]"
34+
>
35+
{pathname !== '/my-store' ? (
36+
<Link
37+
className="w-full px-4 py-2 bg-blue-400 rounded-md"
38+
to="/my-store"
39+
onClick={() => setShowMenu(false)}
40+
>
41+
My Store
42+
</Link>
43+
) : (
44+
<Link
45+
className="w-full px-4 py-2 bg-blue-400 rounded-md"
46+
to="/"
47+
onClick={() => setShowMenu(false)}
48+
>
49+
Home
50+
</Link>
51+
)}
52+
<button className="w-full px-4 py-2 bg-blue-400 rounded-md mt-4" onClick={logoutUser}>
53+
Logout
54+
</button>
55+
</div>
56+
)}
57+
</div>
58+
</div>
59+
);
60+
};
61+
62+
export default Header;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
import { Link } from 'react-router-dom';
3+
4+
type Props = {
5+
itemId: string;
6+
name: string;
7+
price: number;
8+
};
9+
10+
const Item = ({ itemId, name, price }: Props) => {
11+
12+
return (
13+
<div
14+
className="flex flex-col justify-center items-center bg-white/30
15+
border-2 w-36 rounded-md px-6 py-4"
16+
>
17+
<h1 className="font-bold text-xl">{name}</h1>
18+
<p className="mt-4 text-xs">price</p>
19+
<p className="bg-dark w-full text-center rounded-sm py-1">${price}</p>
20+
21+
<Link
22+
to={`/${itemId}`}
23+
className="bg-blue-400 text-dark rounded-sm w-full mt-4
24+
text-center font-semibold hover:shadow-blkSm hover:scale-110
25+
cursor-pointer"
26+
>
27+
Buy
28+
</Link>
29+
</div>
30+
);
31+
};
32+
33+
export default Item;

examples_new/microservices/client/src/context/appContext.tsx

+38-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { createContext, useReducer, useContext, useEffect } from 'react';
22
import { ActionType } from './actions';
33
import reducer from './reducer';
4-
import { customFetch } from '../util/authFetch';
4+
import { customFetch } from '../util/customFetch';
5+
import { ItemDetails } from '../util/types';
56

67
const authFetch = customFetch(3000);
78
// const itemFetch = customFetch(3001);
8-
// const inventoryFetch = customFetch(3002);
9+
const inventoryFetch = customFetch(3002);
910
// const orderFetch = customFetch(3003);
1011

1112
interface Item {
@@ -35,6 +36,9 @@ interface AppContextInterface extends StateInterface {
3536
stopLoading: () => void;
3637
loginUser: (username: string, password: string, isLogin: boolean) => void;
3738
logoutUser: () => void;
39+
getItemsForSale: () => void;
40+
getItemInventory: () => ItemDetails;
41+
getMyStoreItems: () => void;
3842
}
3943

4044
const AppContext = createContext<AppContextInterface>({
@@ -43,6 +47,9 @@ const AppContext = createContext<AppContextInterface>({
4347
stopLoading: () => null,
4448
loginUser: () => null,
4549
logoutUser: () => null,
50+
getItemsForSale: () => null,
51+
getItemInventory: () => null,
52+
getMyStoreItems: () => null,
4653
});
4754

4855
type Props = {
@@ -83,7 +90,7 @@ const AppContextProvider = ({ children }: Props) => {
8390
const logoutUser = async () => {
8491
startLoading();
8592
try {
86-
const response = await authFetch.post('http://localhost:3000/api/auth/logout');
93+
const response = await authFetch.post('/auth/logout');
8794
console.log(response);
8895
dispatch({ type: ActionType.LOGOUT_USER });
8996
} catch (err) {
@@ -106,6 +113,31 @@ const AppContextProvider = ({ children }: Props) => {
106113
stopLoading();
107114
};
108115

116+
// TODO
117+
const getItemsForSale = () => {
118+
console.log('getItemsForSale');
119+
};
120+
121+
// TODO
122+
const getItemInventory = async (itemId: string) => {
123+
console.log('getItemInventory');
124+
startLoading();
125+
try {
126+
const response = await inventoryFetch(`/inventory/getItemInventory/${itemId}`);
127+
stopLoading();
128+
return response.data;
129+
} catch (err) {
130+
stopLoading();
131+
console.log(err);
132+
return null;
133+
}
134+
};
135+
136+
// TODO
137+
const getMyStoreItems = () => {
138+
console.log('getMyStoreItems');
139+
};
140+
109141
return (
110142
<AppContext.Provider
111143
value={{
@@ -114,6 +146,9 @@ const AppContextProvider = ({ children }: Props) => {
114146
stopLoading,
115147
loginUser,
116148
logoutUser,
149+
getItemsForSale,
150+
getItemInventory,
151+
getMyStoreItems,
117152
}}
118153
>
119154
{children} {/* <App /> */}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
1+
import { nanoid } from 'nanoid';
2+
import Item from '../components/Item';
3+
import { testItems } from '../util/testData';
4+
import { useAppContext } from '../context/appContext';
5+
import { useEffect } from 'react';
6+
17
const Home = () => {
2-
return <div>Home</div>;
8+
const { user, getItemsForSale } = useAppContext();
9+
10+
useEffect(() => {
11+
if (user) {
12+
getItemsForSale();
13+
}
14+
// eslint-disable-next-line
15+
}, []);
16+
17+
return (
18+
<div className="flex flex-col justify-center items-center">
19+
<h1 className="text-4xl bg-light text-dark rounded-md px-4 py-2">Items for Sale</h1>
20+
<div className="flex flex-wrap gap-4 w-[85%] mt-8">
21+
{testItems.map(item => (
22+
<Item key={nanoid()} itemId={item.itemId} name={item.name} price={item.price} />
23+
))}
24+
</div>
25+
</div>
26+
);
327
};
428

529
export default Home;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const MyStore = () => {
2+
return <div>MyStore</div>;
3+
};
4+
5+
export default MyStore;

examples_new/microservices/client/src/pages/SharedLayout.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Outlet } from 'react-router-dom';
2+
import Header from '../components/Header';
23

34
const SharedLayout = () => {
45
return (
@@ -7,6 +8,7 @@ const SharedLayout = () => {
78
flex flex-col justify-center items-center
89
bg-dark text-light"
910
>
11+
<Header />
1012
<Outlet />
1113
</main>
1214
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export const testItems = [
2+
{
3+
itemId: '9827569348726534',
4+
name: 'banana',
5+
price: 3.99,
6+
inventory: 10,
7+
},
8+
{
9+
itemId: '9827569348726534',
10+
name: 'VCR',
11+
price: 20.99,
12+
inventory: 3,
13+
},
14+
{
15+
itemId: '9827569348726534',
16+
name: 'coffee',
17+
price: 10.29,
18+
inventory: 134,
19+
},
20+
{
21+
itemId: '9827569348726534',
22+
name: 'plunger',
23+
price: 13.99,
24+
inventory: 48,
25+
},
26+
{
27+
itemId: '9827569348726534',
28+
name: 'scones',
29+
price: 13.99,
30+
inventory: 48,
31+
},
32+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type ItemDetails = {
2+
name: string;
3+
itemId: string;
4+
units: number;
5+
};

examples_new/microservices/client/tailwind.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default {
1010
boxShadow: {
1111
blkSm: '2px 2px 6px rgba(0, 0, 0, 0.35), 3px 3px 6px rgba(0, 0, 0, 0.25)',
1212
blkLg: '6px 6px 10px rgba(0, 0, 0, 0.35), 8px 8px 10px rgba(0, 0, 0, 0.25)',
13+
insetLight: 'inset 3px 3px 6px #ffffff, inset -3px -3px 3px #aeaeae;',
1314
},
1415
keyframes: {
1516
spin: {

0 commit comments

Comments
 (0)