diff --git a/package.json b/package.json
index fe5f54a..c9ad426 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,8 @@
"@mui/styled-engine-sc": "^5.12.0",
"@mui/x-data-grid": "^6.9.2",
"@reduxjs/toolkit": "^1.9.5",
+ "@tanstack/react-query": "^4.29.19",
+ "axios": "^1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.1",
diff --git a/src/App.tsx b/src/App.tsx
index dd001f7..326934e 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -14,6 +14,7 @@ import Error from './scenes/Error';
import Checkout from './scenes/Checkout';
import Cart from './scenes/Cart';
import ProductDetail from './scenes/Shop/fragments/ProductDetail';
+import { QueryClientProvider, useQueryClient } from '@tanstack/react-query';
const App = () => {
const mode = useAppSelector((state) => state.global.mode) as PaletteMode;
@@ -29,7 +30,7 @@ const App = () => {
} />
} />
} />
- } />
+ } />
} />
} />
} />
diff --git a/src/api/index.ts b/src/api/index.ts
new file mode 100644
index 0000000..b176e11
--- /dev/null
+++ b/src/api/index.ts
@@ -0,0 +1 @@
+export * from './products';
diff --git a/src/api/products.ts b/src/api/products.ts
new file mode 100644
index 0000000..4608a88
--- /dev/null
+++ b/src/api/products.ts
@@ -0,0 +1,24 @@
+import axios from '../utils/axios';
+
+export type Product = {
+ id: number;
+ title: string;
+ price: number;
+ description: string;
+ category: string;
+ image: string;
+ rating: Rating;
+};
+
+export type Rating = {
+ rate: number;
+ count: number;
+};
+
+export const getProducts = (): Promise => {
+ return axios.get('/products', { method: 'get' }).then((resp) => resp.data);
+};
+
+export const getProduct = (id: string): Promise => {
+ return axios.get(`/products/${id}`, { method: 'get' }).then((resp) => resp.data);
+};
diff --git a/src/components/Skeleton/CardLoader.tsx b/src/components/Skeleton/CardLoader.tsx
new file mode 100644
index 0000000..517c84c
--- /dev/null
+++ b/src/components/Skeleton/CardLoader.tsx
@@ -0,0 +1,15 @@
+import { Box, Skeleton } from '@mui/material';
+import React from 'react';
+import useStyles from '../../scenes/Dashboard/useStyles';
+
+const SkeletonLoader = React.memo(() => {
+ const classes = useStyles();
+ return (
+
+
+
+
+ );
+});
+
+export default SkeletonLoader;
diff --git a/src/scenes/Dashboard/fragments/FeaturedProducts.tsx b/src/scenes/Dashboard/fragments/FeaturedProducts.tsx
index ff23758..98cd69c 100644
--- a/src/scenes/Dashboard/fragments/FeaturedProducts.tsx
+++ b/src/scenes/Dashboard/fragments/FeaturedProducts.tsx
@@ -1,9 +1,15 @@
+import React, { useState } from 'react';
import { Box, Card, CardMedia, CardContent, Typography, Button, Fade } from '@mui/material';
-import { dataSource } from '../../../data';
-import { useState } from 'react';
import useStyles from '../useStyles';
+import { UseQueryResult } from '@tanstack/react-query';
+import { Product } from '../../../api';
+import SkeletonLoader from '../../../components/Skeleton/CardLoader';
-const FeaturedProducts = () => {
+type FeaturedProductsProps = {
+ query: UseQueryResult;
+};
+
+const FeaturedProducts = ({ query: { error, isLoading, data } }: FeaturedProductsProps) => {
const classes = useStyles();
const [hoveredCard, setHoveredCard] = useState(null);
const [isHovered, setIsHovered] = useState(false);
@@ -18,37 +24,53 @@ const FeaturedProducts = () => {
setIsHovered(false);
};
+ if (isLoading) {
+ return (
+
+ {new Array(8).fill(null).map((_, index) => (
+
+ ))}
+
+ );
+ }
+
return (
Our Products
- {dataSource.map((item) => (
+ {data?.slice(0, 8)?.map((item) => (
handleCardHover(item.id)}
+ onMouseEnter={() => handleCardHover(item.id.toString())}
onMouseLeave={handleCardLeave}
>
- {item?.productMeta?.title}
+ {item?.title}
- {item?.productMeta?.desc}
+ {item?.description}
-
+
+
+ {/* MAIN IMAGE DISPLAY */}
-
-
-
-
-
-
-
-
- SKU : ss0011
+
+
+ {/* RIGHT */}
+
+
+ {data?.title}
-
- Category : Sofa
+
+ Rs {data?.price}
-
- Tags : Single Seater, Luxury
+
+ {data?.description}
-
+
+
+
+ Colors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SKU : {data?.id}
+
+
+ Category : {data?.category}
+
+
+ Tags : {data?.category}
+
+
+
-
-
-
+
+ {/*
-
-
- >
- );
+ */}
+
+ >
+ );
};
export default ProductDetail;
diff --git a/src/scenes/Shop/fragments/ProductList.tsx b/src/scenes/Shop/fragments/ProductList.tsx
index ff46041..8625301 100644
--- a/src/scenes/Shop/fragments/ProductList.tsx
+++ b/src/scenes/Shop/fragments/ProductList.tsx
@@ -19,15 +19,23 @@ import {
PaginationItem,
} from '@mui/material';
import useStyles from '../../Dashboard/useStyles';
-import { dataSource } from '../../../data';
+import { UseQueryResult } from '@tanstack/react-query';
import FlexBetween from '../../../components/FlexBetween';
/* ASSETS */
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
+import SkeletonLoader from '../../../components/Skeleton/CardLoader';
+import { Product } from '../../../api';
+import { useNavigate } from 'react-router-dom';
-const ProductList = () => {
+type ProductListProps = {
+ query: UseQueryResult;
+};
+
+const ProductList = ({ query: { error, isLoading, data } }: ProductListProps) => {
const classes = useStyles();
+ const navigate = useNavigate();
const theme = useTheme();
const [hoveredCard, setHoveredCard] = useState(null);
const [isHovered, setIsHovered] = useState(false);
@@ -57,6 +65,22 @@ const ProductList = () => {
setPage(value);
};
+ if (isLoading) {
+ return (
+
+ {new Array(8).fill(null).map((_, index) => (
+
+ ))}
+
+ );
+ }
+
return (
{
width='90%'
px='4rem'
>
- {dataSource.map((item) => (
+ {data?.map((item) => (
handleCardHover(item.id)}
+ onMouseEnter={() => handleCardHover(item.id.toString())}
onMouseLeave={handleCardLeave}
+ onClick={() => navigate(`/products/${item.id}`)}
+ sx={{ '&:hover': { cursor: 'pointer' } }}
>
- {item?.productMeta?.title}
+ {item?.title}
- {item?.productMeta?.desc}
+ {item?.description}
-
+ {/*
-
+ */}
))}
diff --git a/src/scenes/Shop/index.tsx b/src/scenes/Shop/index.tsx
index 781fc74..5e7c123 100644
--- a/src/scenes/Shop/index.tsx
+++ b/src/scenes/Shop/index.tsx
@@ -2,12 +2,16 @@ import { Box } from '@mui/material';
import Header from '../../components/Header';
import ProductList from './fragments/ProductList';
import Banner from '../../components/Banner';
+import { useQuery } from '@tanstack/react-query';
+import { getProducts } from '../../api';
const Shop = () => {
+ const query = useQuery({ queryKey: ['products'], queryFn: getProducts });
+
return (
<>
-
+
{/* */}
>
diff --git a/src/utils/axios.ts b/src/utils/axios.ts
new file mode 100644
index 0000000..804cffa
--- /dev/null
+++ b/src/utils/axios.ts
@@ -0,0 +1,9 @@
+import axios from 'axios';
+
+const instance = axios.create({
+ baseURL: import.meta.env.VITE_APP_BASE_URL,
+ timeout: 1000,
+ headers: { 'X-Custom-Header': 'foobar' },
+});
+
+export default instance;
diff --git a/yarn.lock b/yarn.lock
index af6343f..6119638 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1704,6 +1704,19 @@
"@svgr/hast-util-to-babel-ast" "^7.0.0"
svg-parser "^2.0.4"
+"@tanstack/query-core@4.29.19":
+ version "4.29.19"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.29.19.tgz#49ccbd0606633d1e55baf3b91ab7cc7aef411b1d"
+ integrity sha512-uPe1DukeIpIHpQi6UzIgBcXsjjsDaLnc7hF+zLBKnaUlh7jFE/A+P8t4cU4VzKPMFB/C970n/9SxtpO5hmIRgw==
+
+"@tanstack/react-query@^4.29.19":
+ version "4.29.19"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.29.19.tgz#6ba187f2d0ea36ae83ff1f67068f53c88ce7b228"
+ integrity sha512-XiTIOHHQ5Cw1WUlHaD4fmVUMhoWjuNJlAeJGq7eM4BraI5z7y8WkZO+NR8PSuRnQGblpuVdjClQbDFtwxTtTUw==
+ dependencies:
+ "@tanstack/query-core" "4.29.19"
+ use-sync-external-store "^1.2.0"
+
"@types/estree@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194"
@@ -1933,6 +1946,20 @@ array-union@^2.1.0:
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
+ integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
+ dependencies:
+ follow-redirects "^1.15.0"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
babel-plugin-macros@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
@@ -2082,6 +2109,13 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
commander@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
@@ -2165,6 +2199,11 @@ deep-is@^0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -2439,6 +2478,20 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
+follow-redirects@^1.15.0:
+ version "1.15.2"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
+ integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
fs-readdir-recursive@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27"
@@ -2739,6 +2792,18 @@ micromatch@^4.0.4:
braces "^3.0.2"
picomatch "^2.3.1"
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -2899,6 +2964,11 @@ prop-types@^15.6.2, prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
punycode@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
@@ -3309,7 +3379,7 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-use-sync-external-store@^1.0.0:
+use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==