Skip to content

Commit cbd6519

Browse files
user search product UI
1 parent d192f48 commit cbd6519

File tree

5 files changed

+282
-76
lines changed

5 files changed

+282
-76
lines changed

src/components/inputs/SearchInput.tsx

+41-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from "react";
44
import { FiSearch } from "react-icons/fi";
55
import "../../styles/SearchInput.scss";
66
import { useAppDispatch, useAppSelector } from "../../store/store";
7-
import { useNavigate } from "react-router-dom";
7+
import { Link, useNavigate } from "react-router-dom";
88
import {
99
searchProduct,
1010
selectSearchResults,
@@ -17,39 +17,63 @@ interface SearchInputProps {
1717
function SearchInput({ className, placeholder }: SearchInputProps) {
1818
const dispatch = useAppDispatch();
1919
const searchResults = useAppSelector(selectSearchResults);
20-
const searchError = useAppSelector(selectSearchError);
2120
const [search, setSearch] = useState("");
21+
const [isFocused, setIsFocused] = useState(false);
22+
const [isHoved, setIsHoved] = useState(false);
23+
2224
const navigate = useNavigate();
25+
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
26+
const value = e.target.value;
27+
setSearch(value);
28+
if (value.trim()) {
29+
dispatch(searchProduct({ name: value.trim() }));
30+
}
31+
};
2332
return (
24-
<div>
25-
<form className={`search-container ${className}`}>
33+
<div className="main-search">
34+
<form
35+
className={`search-container ${className}`}
36+
onSubmit={(e) => {
37+
e.preventDefault();
38+
if (search.trim()) {
39+
navigate(`/search?name=${search.trim()}`);
40+
}
41+
}}
42+
>
2643
<div className="search-icon">
2744
<FiSearch />
2845
</div>
2946
<input
3047
type="text"
3148
placeholder={placeholder}
32-
onChange={(e) => {
33-
setSearch(e.target.value);
34-
dispatch(searchProduct({ name: e.target.value }));
35-
}}
49+
onFocus={() => setIsFocused(true)}
50+
onBlur={() => setIsFocused(false)}
51+
onChange={handleSearchChange}
52+
value={search}
3653
/>
3754
<button
3855
className="search-button"
56+
type="submit"
3957
onClick={() => navigate(`/search?name=${search}`)}
4058
>
4159
Search
4260
</button>
4361
</form>
44-
<div style={{ display: search ? "block" : "none" }}>
45-
{searchResults.length > 0 ? (
46-
searchResults.map((product: any) => (
47-
<p key={product.id}>{product.name}</p>
48-
))
49-
) : (
50-
<p>No product</p>
51-
)}
52-
</div>
62+
{(isFocused || isHoved) && (
63+
<div className="search-result" onMouseEnter={()=> setIsHoved(true)}>
64+
{searchResults.length > 0 ? (
65+
searchResults.map((product: any) => (
66+
<div key={product.id} className="result">
67+
<Link to={`/search?name=${product.name}`} className="link">
68+
<p >{product.name}</p>
69+
</Link>
70+
</div>
71+
)
72+
)
73+
) :null
74+
}
75+
</div>
76+
)}
5377
</div>
5478
);
5579
}

src/pages/Search.tsx

+85-17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
/* eslint-disable */
22
import React, { useEffect, useState } from "react";
33
import { useAppDispatch, useAppSelector } from "../store/store";
4+
import SkewLoader
5+
6+
from "react-spinners/ClipLoader";
7+
import "../styles/search.scss";
8+
import Header from "../components/layout/Header";
9+
import Footer from "../components/layout/Footer";
410
import {
511
searchProduct,
612
selectSearchResults,
713
selectSearchError,
814
} from "../store/features/ProductSlice";
915
import { useLocation } from "react-router-dom";
16+
import { FaChevronDown } from "react-icons/fa6";
17+
import Product from "../components/product/Product";
1018

1119
const SearchBar: React.FC = () => {
1220
const location = useLocation();
@@ -15,6 +23,13 @@ const SearchBar: React.FC = () => {
1523
const category = params.get("category");
1624
const maxPrice = params.get("maxPrice");
1725
const minPrice = params.get("minPrice");
26+
const [loading,setLoading] = useState(false)
27+
useEffect(()=>{
28+
setLoading(true)
29+
setTimeout(()=>{
30+
setLoading(false)
31+
},1000)
32+
},[])
1833

1934
const dispatch = useAppDispatch();
2035
const searchResults = useAppSelector(selectSearchResults);
@@ -30,23 +45,76 @@ const SearchBar: React.FC = () => {
3045
);
3146
}, []);
3247
return (
33-
<div>
34-
<h1>search</h1>
35-
{searchError && <p>Error: {searchError}</p>}
36-
<div>
37-
{searchResults.length > 0 ? (
38-
<ul>
39-
{searchResults.map((product: any) => (
40-
<li key={product.id}>
41-
{product.name} : ${product.price}
42-
</li>
43-
))}
44-
</ul>
45-
) : (
46-
<p>No products found.</p>
47-
)}
48-
</div>
49-
</div>
48+
<>
49+
<Header />
50+
{
51+
loading ? <SkewLoader
52+
53+
color={"#FF6D18"} loading={loading}size={70}/>
54+
:
55+
<>
56+
<div className="product-search">
57+
<div className="main-content-product">
58+
<div className="right-side-bar">
59+
<div className="searchPrice-box">
60+
<span className="product-name">{name}:</span>
61+
<span className="searchSpan-price">Price:</span>
62+
<div className="dropdown-container">
63+
<select className="min-span">
64+
<option value="">Min</option>
65+
<FaChevronDown className="header__selected__iconIcon" />
66+
<option value="10">$10</option>
67+
<option value="20">$20</option>
68+
</select>
69+
<select className="max-span">
70+
<option value="">Max</option>
71+
<FaChevronDown className="header__selected__iconIcon" />
72+
<option value="50">$50</option>
73+
<option value="100">$100</option>
74+
</select>
75+
<span className="searchSpan-price">Discount:</span>
76+
<select className="max-span">
77+
<option value="">Discount</option>
78+
<FaChevronDown className="header__selected__iconIcon" />
79+
<option value="5">5%</option>
80+
<option value="10">10%</option>
81+
</select>
82+
</div>
83+
</div>
84+
</div>
85+
</div>
86+
</div><div className="product-main">
87+
<div className="landing-container">
88+
{false ? (
89+
<div className="loader"></div>
90+
) : searchError ? (
91+
<div className="error-message">
92+
<p>{"Something went wrong. Please try again later."}</p>
93+
</div>
94+
) : (
95+
<div>
96+
<div className="product-list">
97+
{searchResults &&
98+
searchResults.map((product: any) => (
99+
<Product
100+
key={product.id}
101+
images={product.images}
102+
name={product.name}
103+
price={`$${product.price}`}
104+
stock={Number(product.quantity)}
105+
description={product.description}
106+
discount={Number(product.discount.replace("%", ""))} />
107+
))}
108+
</div>
109+
</div>
110+
)}
111+
</div>
112+
</div>
113+
</>
114+
}
115+
116+
<Footer />
117+
</>
50118
);
51119
};
52120

src/styles/Colors.scss

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ $black-2: #232f3e;
1919
$black-3: #131a22;
2020
$secondary-color-2: #edeef0;
2121
$font-family: 'Averia Serif Libre', serif;
22+
$container-color:#D9D9D933

src/styles/Search.scss

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
@import "./Colors";
2+
3+
.product-search {
4+
display: flex;
5+
flex-direction: column;
6+
height: 65px;
7+
background-color: $container-color;
8+
border-bottom: 1px solid #ccc;
9+
10+
.main-content-product {
11+
display: flex;
12+
13+
.right-side-bar {
14+
display: flex;
15+
flex-direction: column;
16+
margin-left: 50px;
17+
height: 40px;
18+
}
19+
20+
.searchPrice-box {
21+
display: flex;
22+
align-items: center;
23+
width: 80rem;
24+
height: 56px;
25+
padding-top: 10px;
26+
padding-bottom: 10px;
27+
line-height: 40px;
28+
margin-left: 5px;
29+
30+
&:not(:last-child) {
31+
margin-bottom: 10px;
32+
}
33+
34+
.product-name {
35+
font-size: 20px;
36+
margin-right: 10px;
37+
width: 30rem;
38+
}
39+
40+
.searchSpan-price {
41+
margin: 0 6px 0 4px;
42+
line-height: 30px;
43+
font-size: 20px;
44+
vertical-align: middle;
45+
display: inline-block;
46+
}
47+
48+
.dropdown-container {
49+
display: flex;
50+
align-items: center;
51+
52+
.min-span,
53+
.max-span,
54+
.discount-span {
55+
display: flex;
56+
align-items: center;
57+
justify-content: space-between;
58+
width: 100px;
59+
height: 30px;
60+
border: 1px solid rgba(255, 109, 24, 0.49);
61+
border-radius: 4px;
62+
padding: 0 5px;
63+
font-size: 15px;
64+
cursor: pointer;
65+
background-color: #fff;
66+
margin-right: 10px;
67+
}
68+
.header__selected__iconIcon {
69+
margin-left: 8px;
70+
color:rgba(255, 109, 24, 0.49);
71+
}
72+
73+
}
74+
}
75+
}
76+
}
77+
.product-main{
78+
height: 500px;
79+
background-color: $container-color;
80+
}

0 commit comments

Comments
 (0)