From 11287318c0665af5611dc0a4c08e15d0d67d0c24 Mon Sep 17 00:00:00 2001 From: Aseer KT Date: Thu, 5 Aug 2021 13:27:32 +0530 Subject: [PATCH 1/5] Rearrange `App.js` --- src/App.js | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/App.js b/src/App.js index 7ad559c..ebca7d0 100644 --- a/src/App.js +++ b/src/App.js @@ -8,33 +8,26 @@ import Homepage from './Components/Homepage/Homepage'; import MyCart from './Components/CartPage/MyCart'; import SignIn from './Components/SignIn/SignIn'; import ProductList from './Components/ProductList/ProductList'; +import SingleProduct from './Components/SingleProduct/SingleProduct'; function App() { const setQuery = useStore(state => state.setQuery); useEffect(() => { setQuery(''); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( - - - - - - - - - - - - - - - + + + + + + From 6c8f73ee3c51be621b1a5d4000f9f802a05bdad0 Mon Sep 17 00:00:00 2001 From: Aseer KT Date: Sat, 7 Aug 2021 08:52:00 +0530 Subject: [PATCH 2/5] single product page --- src/Components/ProductList/ProductItem.jsx | 13 +- src/Components/SingleProduct/ProductCart.jsx | 33 ++++ .../SingleProduct/SingleProduct.jsx | 171 ++++++++++++++++++ src/Data/products/index.js | 4 + src/Data/{products.json => productsData.json} | 0 src/Styles/_resuable.scss | 51 ++++-- src/Styles/_single_pdt.scss | 171 ++++++++++++++++++ src/Styles/style.scss | 3 +- src/utils.js | 12 ++ 9 files changed, 428 insertions(+), 30 deletions(-) create mode 100644 src/Components/SingleProduct/ProductCart.jsx create mode 100644 src/Components/SingleProduct/SingleProduct.jsx rename src/Data/{products.json => productsData.json} (100%) create mode 100644 src/Styles/_single_pdt.scss diff --git a/src/Components/ProductList/ProductItem.jsx b/src/Components/ProductList/ProductItem.jsx index 983ab50..5ba8bd1 100644 --- a/src/Components/ProductList/ProductItem.jsx +++ b/src/Components/ProductList/ProductItem.jsx @@ -1,15 +1,7 @@ import { Link } from 'react-router-dom'; -import { numberWithCommas } from '../../utils'; +import { formatDate, numberWithCommas } from '../../utils'; import Rating from './Rating'; -function formatDate(dt) { - return dt.toLocaleString('en-CA', { - month: 'long', - day: 'numeric', - year: 'numeric', - }); -} - function ProductItem({ product }) { const priceWithoutDiscount = parseInt( (product.price * 100) / (100 - product.discount), @@ -66,8 +58,7 @@ function ProductItem({ product }) {
{/* need to get prime image here */} - - {product.fullfilled && } Get it by + {product.fullfilled && } Get it by {formatDate(deliveryDate)}
diff --git a/src/Components/SingleProduct/ProductCart.jsx b/src/Components/SingleProduct/ProductCart.jsx new file mode 100644 index 0000000..6b91e80 --- /dev/null +++ b/src/Components/SingleProduct/ProductCart.jsx @@ -0,0 +1,33 @@ +import useStore from '../../store'; + +function ProductCart({ product }) { + const user_location = useStore(state => state.user_location); + return ( +
+

+ + +

+
+ + +
+
+ +

Secure transaction

+
+
+ +

Deliver to {user_location}

+
+
+ ); +} + +export default ProductCart; diff --git a/src/Components/SingleProduct/SingleProduct.jsx b/src/Components/SingleProduct/SingleProduct.jsx new file mode 100644 index 0000000..c0dfb1e --- /dev/null +++ b/src/Components/SingleProduct/SingleProduct.jsx @@ -0,0 +1,171 @@ +import { Link, useParams } from 'react-router-dom'; +import { getProductById } from '../../Data/products/index'; +import { capitalizeFirst, formatDate, numberWithCommas } from '../../utils'; +import Rating from '../ProductList/Rating'; +import ProductCart from './ProductCart'; + +function DeliveryFeature() { + const items = [ + { + id: '8zeyta-kx8gfg-fjk4h3-8sto0p', + dataId: 'RETURNS_POLICY', + name: '7 Days Replacement', + image: + 'https://images-na.ssl-images-amazon.com/images/G/31/A2I-Convert/mobile/IconFarm/icon-returns._CB484059092_.png', + }, + { + id: 'ibgdh0-jdltm8-4exan-3k9cpe', + dataId: 'AMAZON_DELIVERED', + name: 'Amazon Delivered', + image: + 'https://images-na.ssl-images-amazon.com/images/G/31/A2I-Convert/mobile/IconFarm/icon-amazon-delivered._CB485933725_.png', + }, + { + id: '6h83sn-2ix3xj-piu7hy-gldgb6', + dataId: 'WARRANTY', + name: '1 Year Warranty', + image: + 'https://images-na.ssl-images-amazon.com/images/G/31/A2I-Convert/mobile/IconFarm/icon-warranty._CB485935626_.png', + }, + { + id: 'ka0dd9-f9ibnx-cv0w2n-b0lldt', + dataId: 'NO_CONTACT_DELIVERY', + name: 'No-Contact Delivery', + image: + 'https://images-na.ssl-images-amazon.com/images/G/31/A2I-Convert/mobile/IconFarm/No_contact_delivery_final._CB432269791_.png', + }, + ]; + + return ( +
+ {items.map(i => ( +
+
+ {i.name} +
+
+ + {i.name}{' '} + +
+
+ ))} +
+ ); +} + +function SingleProduct() { + const { productId } = useParams(); + const product = getProductById(productId); + const priceWithoutDiscount = parseInt( + (product.price * 100) / (100 - product.discount), + ); + let deliveryDate = new Date(); + deliveryDate.setDate(deliveryDate.getDate() + product.deliveryDays); + + return ( +
+
+ {product.name} +
+
+

{product.name}

+

+ Category:{' '} + + {capitalizeFirst(product.category)} + +

+
+ + + + {numberWithCommas(product.numReviews)} ratings + +
+ {product.fullfilled && ( +

+ fullfilled +

+ )} +
+ + + + + + + + + + + + + + + + + +
M.R.P.: + ₹{numberWithCommas(priceWithoutDiscount.toFixed(2))} +
Deal Price: + ₹{numberWithCommas(product.price.toFixed(2))} +
You Save: + ₹ + {numberWithCommas( + (priceWithoutDiscount - product.price).toFixed(2), + )}{' '} + ({product.discount}%) +
Inclusive of all taxes
+
+

+ + {product.price > 500 ? 'FREE Delivery' : 'Delivery at'}: + + {formatDate(deliveryDate)} + Details +

+ + In Stock. +

+ Sold by Random Seller + {product.fullfilled && ( + + {' '} + and Fulfilled by Amazon + + )} +

+

+ {product.description} Lorem ipsum dolor, sit amet consectetur + adipisicing elit. Nobis corporis dolore eos veritatis deserunt non? + Consequuntur possimus placeat iste earum at quos facere facilis + dolores voluptate, libero officiis itaque nesciunt.{' '} +

+
+ +
+ ); +} + +export default SingleProduct; diff --git a/src/Data/products/index.js b/src/Data/products/index.js index f35a490..c0fc3df 100644 --- a/src/Data/products/index.js +++ b/src/Data/products/index.js @@ -39,4 +39,8 @@ function shuffle(array) { const products = shuffle([...mobiles, ...laptops]); +export function getProductById(id) { + return products.find(p => p.id === id); +} + export default products; diff --git a/src/Data/products.json b/src/Data/productsData.json similarity index 100% rename from src/Data/products.json rename to src/Data/productsData.json diff --git a/src/Styles/_resuable.scss b/src/Styles/_resuable.scss index 9099254..da2f397 100644 --- a/src/Styles/_resuable.scss +++ b/src/Styles/_resuable.scss @@ -1,25 +1,40 @@ .sign_in_btn { - background-color: #ffd814; - padding: 8px 5px; - display: block; - border: none; - border-radius: 8px; - width: 100%; - text-align: center; - font-size: 13px; - margin: 10px 0; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.061); - cursor: pointer; - &:hover { - background-color: #f6d115; - } - &:active { - background-color: #ceac06; - } + background-color: #ffd814; + padding: 8px 5px; + display: block; + border: none; + border-radius: 8px; + width: 100%; + text-align: center; + font-size: 13px; + margin: 10px 0; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.061); + cursor: pointer; + &:hover { + background-color: #f6d115; + } + &:active { + background-color: #ceac06; + } } .bold { - font-weight: 600; + font-weight: 600; +} + +.amz-link { + text-decoration: none; + color: #007185; + + &:hover { + text-decoration: underline; + cursor: pointer; + color: #c7511f; + } + + &.no-underline:hover { + text-decoration: none; + } } // Max-width: 1450px or 1500px diff --git a/src/Styles/_single_pdt.scss b/src/Styles/_single_pdt.scss new file mode 100644 index 0000000..842ec28 --- /dev/null +++ b/src/Styles/_single_pdt.scss @@ -0,0 +1,171 @@ +.singleProduct { + display: grid; + grid-template-columns: 40% auto 244px; + gap: 1.4rem; + max-width: 1500px; + margin: 0 auto; + padding: 3rem 1rem; + background-color: #fff; + + .product-image { + display: grid; + justify-content: center; + padding: 1rem 2rem; + img { + max-width: 500px; + min-width: 250px; + object-fit: contain; + } + } + + .product-details { + font-size: 15px; + h1 { + font-size: 1.3rem; + font-weight: 400; + line-height: 32px; + margin-bottom: 1rem; + } + + .ratings { + margin-top: 5px; + display: flex; + align-items: center; + gap: 3px; + color: rgb(0, 105, 175); + cursor: pointer; + filter: drop-shadow(0 0 3px rgba (0, 0, 0, 0.473)); + + .reviews { + color: #007185; + font-size: 14px; + margin-left: 0.6rem; + &:hover { + color: #c7511f; + text-decoration: underline; + } + } + } + + .fullfilled-image { + height: 20px; + margin: 0.3rem 0; + object-fit: contain; + } + + .price-details { + margin: 0.3rem 0; + border-top: 1px solid lightgray; + padding-top: 0.8rem; + table { + border-spacing: 0.5rem 0.2rem; + th { + text-align: right; + color: #595959; + font-weight: normal; + font-size: 14px; + line-height: 20px; + } + + tr { + font-size: 14px; + line-height: 20px; + } + + .strike { + text-decoration: line-through; + color: #595959; + } + + .price { + color: #b12704; + font-size: 18px; + line-height: 24px; + } + .save { + color: #b12704; + } + } + } + .delivery-info { + display: flex; + align-items: center; + font-size: 14px; + .free-delivery { + margin-right: 0.4rem; + } + strong { + margin-right: 0.4rem; + } + } + .icon-farm-wrapper { + display: flex; + font-size: 12px; + text-align: center; + margin: 0.8rem 0; + padding-bottom: 0.3rem; + width: max-content; + border-bottom: 1px solid lightgray; + .icon-content { + width: 80%; + margin: 0 auto; + .amz-link:hover { + text-decoration: none; + } + } + } + .stock { + display: inline-block; + color: green; + font-size: 1rem; + margin: 0.3rem 0 0.7rem; + } + } + + .product-cart { + padding: 1.4rem; + border-radius: 5px; + border: 1px solid lightgray; + + height: max-content; + + select { + margin-right: 0.4rem; + outline: none; + padding: 0.3rem; + border-radius: 0.3rem; + cursor: pointer; + background-color: #f5f5f5; + } + .sign_in_btn { + border-radius: 999px; + } + .buy_now_btn { + background: #ffa41c; + border-color: #ff8f00; + &:hover { + background: #fa8900; + border-color: #e3931e; + } + } + + .delivery-details { + font-size: small; + display: flex; + align-items: center; + p { + margin-left: 0.3rem; + } + } + .secure-transaction { + font-size: 14px; + margin: 0.5rem 0; + display: flex; + align-items: center; + color: gray; + p { + margin-left: 0.3rem; + } + } + } +} diff --git a/src/Styles/style.scss b/src/Styles/style.scss index 1d10c05..680774d 100644 --- a/src/Styles/style.scss +++ b/src/Styles/style.scss @@ -19,4 +19,5 @@ body { @import 'sign-in'; @import 'cart'; @import 'footer'; -@import 'products'; \ No newline at end of file +@import 'products'; +@import 'single_pdt'; diff --git a/src/utils.js b/src/utils.js index b764983..16c6a04 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,15 @@ export function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } + +export function capitalizeFirst(str) { + return str[0].toUpperCase() + str.slice(1, str.length); +} + +export function formatDate(dt) { + return dt.toLocaleString('en-CA', { + month: 'long', + day: 'numeric', + year: 'numeric', + }); +} From 12efaeda206c85b4a0fa1c8ebe1717d606c1798d Mon Sep 17 00:00:00 2001 From: Aseer KT Date: Sat, 7 Aug 2021 09:11:56 +0530 Subject: [PATCH 3/5] Fix numberWithCommas util function --- src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.js b/src/utils.js index 16c6a04..3dcad3a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,5 @@ export function numberWithCommas(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + return x.toLocaleString('en-IN'); } export function capitalizeFirst(str) { From e4daab0569133f3bc624f6e90c20c21f648348d8 Mon Sep 17 00:00:00 2001 From: Aseer KT Date: Sat, 7 Aug 2021 09:25:27 +0530 Subject: [PATCH 4/5] Removed Decimel for Price display --- src/Components/SingleProduct/SingleProduct.jsx | 13 ++++--------- src/utils.js | 6 +++++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Components/SingleProduct/SingleProduct.jsx b/src/Components/SingleProduct/SingleProduct.jsx index c0dfb1e..b699470 100644 --- a/src/Components/SingleProduct/SingleProduct.jsx +++ b/src/Components/SingleProduct/SingleProduct.jsx @@ -113,23 +113,18 @@ function SingleProduct() { M.R.P.: - ₹{numberWithCommas(priceWithoutDiscount.toFixed(2))} + ₹{numberWithCommas(priceWithoutDiscount)} Deal Price: - - ₹{numberWithCommas(product.price.toFixed(2))} - + ₹{numberWithCommas(product.price)} You Save: - ₹ - {numberWithCommas( - (priceWithoutDiscount - product.price).toFixed(2), - )}{' '} - ({product.discount}%) + ₹{numberWithCommas(priceWithoutDiscount - product.price)} ( + {product.discount}%) diff --git a/src/utils.js b/src/utils.js index 3dcad3a..d92649b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,9 @@ export function numberWithCommas(x) { - return x.toLocaleString('en-IN'); + return x.toLocaleString('en-IN', { + maximumFractionDigits: 2, + style: 'currency', + currency: 'INR', + }); } export function capitalizeFirst(str) { From 9f77d10c1e1d2c9f8a99b9a5a7168781fcee6a8e Mon Sep 17 00:00:00 2001 From: Aseer KT Date: Sat, 7 Aug 2021 11:38:05 +0530 Subject: [PATCH 5/5] Removed currency from number formatting --- src/utils.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/utils.js b/src/utils.js index d92649b..3dcad3a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,9 +1,5 @@ export function numberWithCommas(x) { - return x.toLocaleString('en-IN', { - maximumFractionDigits: 2, - style: 'currency', - currency: 'INR', - }); + return x.toLocaleString('en-IN'); } export function capitalizeFirst(str) {