Skip to content

Commit 5051709

Browse files
rostyk-kanafotskyyShaun Maharaj
andauthored
MT-2823 Search (#34)
* Added search bar, facets, pagination * Updated search page for mobile * Updated header * TS error fix * Code Cleanup * - README update * - update README for mentioning Shopkit and JS-SDK * Fixed issues mentioned in PR Comments * Removed unused tags * Fixed PR comments. Updated search styles. * - set demo link to https, fix Product.tsx * Mobile styles updates Co-authored-by: Shaun Maharaj <Shaun.Maharaj@elasticpath.com>
1 parent 635a01f commit 5051709

38 files changed

+1143
-65
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313

1414
The Elastic Path Commerce Cloud REACT PWA Reference Storefront is a flexible e-commerce website built on Elastic Path’s RESTful e-commerce API. The storefront uses the e-commerce capabilities provided by Elastic Path Commerce Cloud and gets data in a RESTful manner.
1515

16+
The storefront uses the [Elastic Path Commerce Cloud JavaScript SDK](https://github.com/moltin/js-sdk) for all Elastic Path Commerce Cloud API requests, and [Elastic Path Commerce Cloud Embeddable Cart + Checkout](https://github.com/moltin/shopkit) for the Cart and Checkout experiences.
17+
1618
> 💳 Use the test card 4242 4242 4242 4242, any future expiry date, and any CVC below to checkout.
1719
18-
[Demo](http://epcc-reference.elasticpath.com/)
20+
[Demo](https://epcc-reference.elasticpath.com/)
1921

2022
## Documentation 📖
2123

@@ -24,7 +26,8 @@ The Elastic Path Commerce Cloud REACT PWA Reference Storefront is a flexible e-c
2426
Before you begin, ensure that you have the following accounts set up:
2527

2628
- [Elastic Path Commerce Cloud account](https://dashboard.elasticpath.com/login)
27-
- [Stripe account](https://dashboard.stripe.com/) - Stripe is used as the payment gateway. From your [Dashboard](https://dashboard.elasticpath.com), configure Stripe as the payment gateway from your.
29+
- [Stripe account](https://dashboard.stripe.com/) - Stripe is used as the payment gateway. From your [Dashboard](https://dashboard.elasticpath.com), configure Stripe as the payment gateway.
30+
- [Algolia account](https://www.algolia.com/) - Algolia is used for search functionality to display search results, facets, and filtering.
2831

2932
### Start Building the Storefront
3033

@@ -62,6 +65,9 @@ Parameters that require configuration are in the `./src/config.ts` file:
6265
|`stripeKey`| Required| String| Stripe publishable API key.|
6366
|`categoryPageSize`| Required| String| Maximum number of products to display on a category page.|
6467
|`maxCompareProducts`| Required| String| Maximum number of products to display in compare view.|
68+
|`algoliaAppId`| Required| String| Algolia application identifier.|
69+
|`algoliaApiKey`| Required| String| Algolia API key used to read records.|
70+
|`algoliaIndexName`| Required| String| Name of Algolia index used for search functions.|
6571

6672
## Contributors ✨
6773

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"@types/node": "^12.0.0",
88
"@types/react": "^16.9.0",
99
"@types/react-dom": "^16.9.0",
10+
"@types/react-instantsearch-dom": "^6.3.0",
1011
"@types/react-router-dom": "^5.1.5",
12+
"algoliasearch": "^4.3.0",
1113
"app-localizer": "^1.2.2",
1214
"constate": "^2.0.0",
1315
"css-reset-and-normalize": "^2.1.0",
@@ -19,6 +21,7 @@
1921
"react-cool-onclickoutside": "^1.5.2",
2022
"react-detect-offline": "^2.4.0",
2123
"react-dom": "^16.13.1",
24+
"react-instantsearch-dom": "^6.6.0",
2225
"react-responsive-modal": "^4.0.1",
2326
"react-router-dom": "^5.2.0",
2427
"react-script-hook": "^1.1.1",

src/App.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,11 @@
2626
padding-right: calc(#{$maxScrollWidth} - 100vw + 100%);
2727
}
2828
}
29+
30+
@media (max-width: $mobileWidth - 1px) {
31+
.app {
32+
&__header {
33+
padding: 0;
34+
}
35+
}
36+
}

src/App.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import React from 'react';
22
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
33
import useScript from 'react-script-hook';
4+
import algoliasearch from 'algoliasearch/lite';
5+
import { Configure, InstantSearch } from 'react-instantsearch-dom';
46
import { routes } from './routes';
57
import { config } from './config';
68
import { AppStateProvider } from './app-state';
@@ -16,10 +18,17 @@ const App: React.FC = () => {
1618
'data-moltin-stripe-publishable-key': config.stripeKey
1719
});
1820

21+
const searchClient = algoliasearch(
22+
config.algoliaAppId,
23+
config.algoliaApiKey
24+
);
25+
1926
return (
2027
<Router>
2128
<AppStateProvider>
22-
<div className="app">
29+
<InstantSearch searchClient={searchClient} indexName={config.algoliaIndexName}>
30+
<Configure hitsPerPage={8}/>
31+
<div className="app">
2332
<header className="app__header">
2433
<AppHeader />
2534
</header>
@@ -39,6 +48,7 @@ const App: React.FC = () => {
3948
<CompareOverlay />
4049
</aside>
4150
</div>
51+
</InstantSearch>
4252
</AppStateProvider>
4353
</Router>
4454
);

src/AppHeader.scss

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,27 @@
1212
}
1313

1414
&__logo {
15+
padding: 0 20px 0 60px;
16+
}
17+
18+
&__search {
1519
flex: 1;
16-
padding-left: 40px;
1720
}
1821

19-
&__account {
22+
&__account, &__language, &__moltincartcontainer {
2023
margin-right: 20px;
2124
}
2225

2326
&__language {
2427
margin-right: 20px;
2528
}
2629

30+
&__container {
31+
width: 100%;
32+
}
33+
2734
&__moltincartcontainer {
2835
flex: 0 0 auto;
29-
padding-right: calc(#{$maxScrollWidth} - 100vw + 100%);
3036
}
3137

3238
.toggle-btn {
@@ -38,16 +44,6 @@
3844
width: 100%
3945
}
4046

41-
@media(max-width: $tabletWidth) {
42-
.toggle-btn {
43-
display: inline-block;
44-
}
45-
46-
&__logo {
47-
padding-left: 50px;
48-
}
49-
}
50-
5147
&__networkoffline {
5248
width: 50%;
5349
padding: 15px;
@@ -61,4 +57,32 @@
6157
background-color: adjust-color($color: $secondAccentColor, $lightness: 65%);
6258
border: 1px solid adjust-color($color: $secondAccentColor, $lightness: 60%);
6359
}
60+
61+
@media(max-width: $tabletWidth) {
62+
.toggle-btn {
63+
display: inline-block;
64+
}
65+
66+
&__logo {
67+
padding-left: 50px;
68+
}
69+
}
70+
71+
@media (max-width: $mobileWidth) {
72+
&__search {
73+
flex: 0;
74+
}
75+
76+
&__logo {
77+
flex: 1px;
78+
}
79+
80+
&__accountm,
81+
&__search,
82+
&__language,
83+
&__moltincartcontainer,
84+
&__account {
85+
margin-right: 10px;
86+
}
87+
}
6488
}

src/AppHeader.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ import { Offline } from 'react-detect-offline';
55
import { ImageContainer } from './ImageContainer';
66
import { useTranslation } from './app-state';
77
import { LanguageDropdown } from './LanguageDropdown';
8-
import './AppHeader.scss';
8+
import { SearchBar } from './SearchBar';
99
import { AccountDropdown } from './AccountDropdown';
10-
import headerLogo from './images/site-images/Company-Logo.svg';
1110
import { Navigation } from "./Navigation";
11+
12+
import headerLogo from './images/site-images/Company-Logo.svg';
13+
14+
import './AppHeader.scss';
15+
1216
export const AppHeader: React.FC = () => {
1317
const { t } = useTranslation();
1418
return (
@@ -19,15 +23,18 @@ export const AppHeader: React.FC = () => {
1923
<ImageContainer imgUrl={headerLogo} imgClassName="logo-image" alt="logoImage"/>
2024
</Link>
2125
</div>
22-
<div className="appheader__account">
23-
<AccountDropdown />
26+
<div className="appheader__search">
27+
<SearchBar />
2428
</div>
2529
<div className="appheader__language">
2630
<LanguageDropdown />
2731
</div>
2832
<div className="appheader__moltincartcontainer">
2933
<span className="moltin-cart-button"></span>
3034
</div>
35+
<div className="appheader__account">
36+
<AccountDropdown />
37+
</div>
3138
</div>
3239
<div className="appheader__navigation">
3340
<Navigation />

src/Availability.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.availability {
2+
display: inline-block;
3+
margin-top: 10px;
4+
text-transform: uppercase;
5+
font-size: 10px;
6+
padding: 5px 10px;
7+
border: 1px solid hsl(0, 0, 80%);
8+
border-radius: 16px;
9+
}

src/Availability.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import { useTranslation } from './app-state';
3+
4+
import './Availability.scss';
5+
6+
7+
interface AvailabilityProps {
8+
available: boolean,
9+
}
10+
11+
export const Availability: React.FC<AvailabilityProps> = (props) => {
12+
const { available } = props;
13+
14+
const { t } = useTranslation();
15+
16+
return (
17+
<div className="availability">
18+
{available ? t('available') : t('out-of-stock')}
19+
</div>
20+
);
21+
};

src/CompareProducts.scss

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,6 @@
5353
margin-top: 10px;
5454
}
5555

56-
#{$block}__availability {
57-
margin-top: 10px;
58-
display: inline-block;
59-
margin-top: 10px;
60-
text-transform: uppercase;
61-
font-size: 10px;
62-
padding: 5px 10px;
63-
border: 1px solid hsl(0, 0, 80%);
64-
border-radius: 16px;
65-
}
66-
6756
#{$block}__addtocart {
6857
margin-top: 16px;
6958
}

src/CompareProducts.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { useCompareProducts, useTranslation } from './app-state';
33
import { ProductMainImage } from './ProductMainImage';
4+
import { Availability } from './Availability';
45
import { Product } from './service';
56
import { isProductAvailable } from './helper';
67
import { ReactComponent as RecycleBinIcon } from './images/icons/ic_trash.svg';
@@ -43,7 +44,7 @@ export const CompareProducts: React.FC = () => {
4344
<td key={product.id}>
4445
<div className="compareproducts__name">{product.name}</div>
4546
<div className="compareproducts__price">{product.meta.display_price.without_tax.formatted}</div>
46-
<div className="compareproducts__availability">{isProductAvailable(product) ? t('available') : t('out-of-stock')}</div>
47+
<Availability available={isProductAvailable(product)} />
4748
<div className="compareproducts__addtocart">
4849
<span
4950
className="moltin-buy-button"

0 commit comments

Comments
 (0)