Skip to content

Commit b0f2c96

Browse files
committed
Video-45-Product-Search-Bar
1 parent fdd3a71 commit b0f2c96

7 files changed

Lines changed: 83 additions & 16 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ $ cd node-javascript-ecommerce
4444
```
4545
MONGODB_URL=mongodb://localhost/jsamazona
4646
JWT_SECRET=somethingsecret
47-
PAYPAL_CLIENT_ID=db
47+
PAYPAL_CLIENT_ID="your paypal client id" or sb
4848
```
4949

5050
### 4. Run Backend
@@ -81,7 +81,7 @@ $ npm start
8181

8282
## Support
8383

84-
- Q/A: https://webacademy.pro/amazona
84+
- Q/A: https://codingwithbasir.com
8585
- Contact Instructor: [Basir](mailto:basir.jafarzadeh@gmail.com)
8686

8787

backend/routers/productRouter.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@ const productRouter = express.Router();
77
productRouter.get(
88
'/',
99
expressAsyncHandler(async (req, res) => {
10-
const products = await Product.find({});
10+
const searchKeyword = req.query.searchKeyword
11+
? {
12+
name: {
13+
$regex: req.query.searchKeyword,
14+
$options: 'i',
15+
},
16+
}
17+
: {};
18+
const products = await Product.find({ ...searchKeyword });
1119
res.send(products);
1220
})
1321
);

frontend/src/api.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import axios from 'axios';
22
import { apiUrl } from './config';
33
import { getUserInfo } from './localStorage';
44

5-
export const getProducts = async () => {
5+
export const getProducts = async ({ searchKeyword = '' }) => {
66
try {
7+
let queryString = '?';
8+
if (searchKeyword) queryString += `searchKeyword=${searchKeyword}&`;
9+
710
const response = await axios({
8-
url: `${apiUrl}/api/products`,
11+
url: `${apiUrl}/api/products${queryString}`,
912
method: 'GET',
1013
headers: {
1114
'Content-Type': 'application/json',

frontend/src/components/Header.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import { getUserInfo } from '../localStorage';
2+
import { parseRequestUrl } from '../utils';
23

34
const Header = {
45
render: () => {
56
const { name, isAdmin } = getUserInfo();
7+
const { value } = parseRequestUrl();
68
return `
79
<div class="brand">
810
<a href="/#/">jsamazona</a>
911
</div>
12+
<div class="search">
13+
<form class="search-form" id="search-form">
14+
<input type="text" name="q" id="q" value="${value || ''}" />
15+
<button type="submit"><i class="fa fa-search"></i></button>
16+
</form>
17+
</div>
1018
<div>
1119
${
1220
name
@@ -17,6 +25,14 @@ const Header = {
1725
${isAdmin ? `<a href="/#/dashboard">Dashboard</a>` : ''}
1826
</div>`;
1927
},
20-
after_render: () => {},
28+
after_render: () => {
29+
document
30+
.getElementById('search-form')
31+
.addEventListener('submit', async (e) => {
32+
e.preventDefault();
33+
const searchKeyword = document.getElementById('q').value;
34+
document.location.hash = `/?q=${searchKeyword}`;
35+
});
36+
},
2137
};
2238
export default Header;

frontend/src/srceens/HomeScreen.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import axios from 'axios';
21
import Rating from '../components/Rating';
32
import { getProducts } from '../api';
3+
import { parseRequestUrl } from '../utils';
44

55
const HomeScreen = {
66
render: async () => {
7-
const products = await getProducts();
7+
const { value } = parseRequestUrl();
8+
const products = await getProducts({ searchKeyword: value });
89
if (products.error) {
910
return `<div class="error">${products.error}</div>`;
1011
}

frontend/src/utils.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import { getCartItems } from './localStorage';
22

33
export const parseRequestUrl = () => {
4-
const url = document.location.hash.toLowerCase();
5-
const request = url.split('/');
4+
const address = document.location.hash.slice(1).split('?')[0];
5+
const queryString =
6+
document.location.hash.slice(1).split('?').length === 2
7+
? document.location.hash.slice(1).split('?')[1]
8+
: '';
9+
10+
const url = address.toLowerCase() || '/';
11+
const r = url.split('/');
12+
const q = queryString.split('=');
613
return {
7-
resource: request[1],
8-
id: request[2],
9-
verb: request[3],
14+
resource: r[1],
15+
id: r[2],
16+
verb: r[3],
17+
name: q[0],
18+
value: q[1],
1019
};
1120
};
1221
export const rerender = async (component) => {
13-
document.getElementById(
14-
'main-container'
15-
).innerHTML = await component.render();
22+
document.getElementById('main-container').innerHTML =
23+
await component.render();
1624
await component.after_render();
1725
};
1826

frontend/style.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,34 @@ td {
456456
.charts > div {
457457
flex: 1;
458458
}
459+
/* search */
460+
461+
.search {
462+
width: 40%;
463+
}
464+
form.search-form input[type='text'] {
465+
float: left;
466+
width: 80%;
467+
border-right: none;
468+
border-top-right-radius: 0;
469+
border-bottom-right-radius: 0;
470+
}
471+
form.search-form button {
472+
float: left;
473+
width: 40px;
474+
background: #f0c040;
475+
476+
border-left: none;
477+
cursor: pointer;
478+
border-top-left-radius: 0;
479+
border-bottom-left-radius: 0;
480+
}
481+
form.search-form button:hover {
482+
background: #0b7dda;
483+
}
484+
/* Clear floats */
485+
form.search-form::after {
486+
content: '';
487+
clear: both;
488+
display: table;
489+
}

0 commit comments

Comments
 (0)