├── .eslintrc.json ├── README.md ├── public ├── favicon.ico ├── vercel.svg ├── img │ ├── social │ │ ├── linkedin.svg │ │ ├── email.svg │ │ └── github.svg │ ├── profile_pic.svg │ └── hero.svg └── next.svg ├── jsconfig.json ├── postcss.config.js ├── src ├── middleware.js ├── utils │ └── capitalizeFirstLetter.js ├── pages │ ├── api │ │ ├── hello.js │ │ └── auth │ │ │ └── [...nextauth].js │ ├── auth │ │ ├── view-all-user.js │ │ └── profile.js │ ├── _document.js │ ├── index.js │ ├── products │ │ ├── order │ │ │ └── index.js │ │ ├── printer │ │ │ └── index.jsx │ │ ├── vr │ │ │ └── index.jsx │ │ ├── view-all-products │ │ │ └── index.jsx │ │ ├── laptop-battery │ │ │ └── index.jsx │ │ ├── smart-watch │ │ │ └── index.jsx │ │ ├── television-startech │ │ │ └── index.jsx │ │ ├── mobile-phone │ │ │ └── index.jsx │ │ ├── portable-power-station │ │ │ └── index.jsx │ │ ├── laptop │ │ │ └── index.jsx │ │ ├── earbuds │ │ │ └── index.jsx │ │ ├── gimbal │ │ │ └── index.jsx │ │ ├── drone │ │ │ └── index.jsx │ │ ├── headphone │ │ │ └── index.jsx │ │ ├── cc-camera │ │ │ └── index.jsx │ │ ├── graphics-card │ │ │ └── index.jsx │ │ ├── action-camera │ │ │ └── index.jsx │ │ ├── gaming-console │ │ │ └── index.jsx │ │ ├── bluetooth-speakers │ │ │ └── index.jsx │ │ └── pc-builder │ │ │ └── index.jsx │ ├── _app.js │ ├── add-to-cart │ │ └── index.js │ ├── 404.js │ ├── product │ │ └── [productId].js │ ├── categories │ │ └── [categoryName].js │ ├── product-details │ │ └── [productId].js │ ├── profile │ │ └── index.js │ ├── add-featehr.js │ ├── build-pc.js │ ├── sign-in.js │ ├── sign-up.js │ └── add-product.js ├── components │ ├── Shared │ │ ├── Card │ │ │ ├── KeyFeatures.jsx │ │ │ ├── HomePageCard.jsx │ │ │ ├── ViewCart.jsx │ │ │ └── Card.jsx │ │ ├── SingleCard │ │ │ ├── KeyFeatures.jsx │ │ │ └── Card.jsx │ │ ├── Navbar │ │ │ ├── SubNavbar.js │ │ │ ├── Navbar.js │ │ │ ├── MobileNavbar.js │ │ │ └── MainNavbar.js │ │ ├── Loading │ │ │ └── LoadingSpinner.jsx │ │ ├── Loader │ │ │ └── Loader.jsx │ │ ├── Footer │ │ │ └── Footer.js │ │ ├── SidebarMenu │ │ │ └── SidebarMenu.js │ │ └── AddToCart │ │ │ └── Card.js │ ├── ImageBB │ │ └── imageUpload.jsx │ ├── FeedbackForm │ │ ├── FeedbackForm.js │ │ └── FeedFrom.js │ ├── Categories │ │ ├── CategoriesProduct.js │ │ └── Categories.js │ ├── UI │ │ ├── Dropdown.js │ │ └── Search.js │ ├── Product │ │ ├── ViewOrderProduct.js │ │ ├── ProductFeed.js │ │ ├── Order.js │ │ ├── Product.js │ │ └── ProductDetails.js │ ├── Layout │ │ └── Layout.js │ ├── Banner │ │ └── Banner.js │ ├── BuildProduct │ │ └── BuildProduct.js │ ├── User │ │ ├── DeleteUser.jsx │ │ ├── RoleChangeModal.jsx │ │ └── ViewAllUser.jsx │ └── ChooseUs │ │ └── ChooseUs.js ├── redux │ ├── features │ │ ├── categories │ │ │ └── categoriesApi.js │ │ ├── product │ │ │ └── productApi.js │ │ ├── userFeedBack │ │ │ └── FeedBack.js │ │ ├── productFeather │ │ │ ├── productFeather.js │ │ │ └── products.js │ │ ├── api │ │ │ └── apiSlice.js │ │ ├── addToCard │ │ │ └── addToCard.js │ │ ├── auth │ │ │ └── userAuth.js │ │ └── pcbuild │ │ │ └── pcbuildSlice.js │ ├── Slice │ │ ├── userSlice.js │ │ └── authSlice.js │ ├── app │ │ └── store.js │ └── store │ │ └── store.js ├── constants │ └── constants.js └── styles │ └── globals.css ├── next.config.js ├── .gitignore ├── tailwind.config.js └── package.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | // eslintrc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🐳 Hazrat Ali 2 | 3 | # 🍏 Programmer || Software Engineering 4 | 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Gadget-Galaxy-Frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | // js config json -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | 8 | // postcss config -------------------------------------------------------------------------------- /src/middleware.js: -------------------------------------------------------------------------------- 1 | export { default } from "next-auth/middleware"; 2 | 3 | export const config = { matcher: ["/add-to-cartaaaa", "/check-out"] }; 4 | -------------------------------------------------------------------------------- /src/utils/capitalizeFirstLetter.js: -------------------------------------------------------------------------------- 1 | export const capitalizeFirstLetter = (string) => { 2 | return string.charAt(0).toUpperCase() + string.slice(1); 3 | }; 4 | 5 | -------------------------------------------------------------------------------- /src/pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: 'John Doe' }) 5 | } 6 | -------------------------------------------------------------------------------- /src/pages/api/auth/[...nextauth].js: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth"; 2 | 3 | export const authOptions = { 4 | providers: [ 5 | ], 6 | // pages: { 7 | // signIn: "/sign-in" 8 | // } 9 | }; 10 | 11 | export default NextAuth(authOptions); 12 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | images: { 5 | domains: ["avatars.githubusercontent.com", "www.startech.com.bd"], 6 | }, 7 | }; 8 | // next config 9 | module.exports = nextConfig; 10 | -------------------------------------------------------------------------------- /src/pages/auth/view-all-user.js: -------------------------------------------------------------------------------- 1 | import ViewAllUser from '@/components/User/ViewAllUser'; 2 | import React from 'react'; 3 | 4 | const Index = () => { 5 | return ( 6 |
7 | < ViewAllUser /> 8 |
9 | ); 10 | }; 11 | 12 | export default Index; -------------------------------------------------------------------------------- /src/components/Shared/Card/KeyFeatures.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const KeyFeatures = ({ item }) => { 4 | return ( 5 |
6 | {!item.key ? `${item.feature}` : `${item.key} : ${item.feature}`} 7 |
8 | ); 9 | }; 10 | 11 | export default KeyFeatures; 12 | -------------------------------------------------------------------------------- /src/pages/_document.js: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document' 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Shared/SingleCard/KeyFeatures.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const KeyFeatures = ({ item }) => { 4 | return ( 5 |
6 | {!item.key ? `${item.feature}` : `${item.key} : ${item.feature}`} 7 |
8 | ); 9 | }; 10 | 11 | export default KeyFeatures; 12 | -------------------------------------------------------------------------------- /src/redux/features/categories/categoriesApi.js: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | const categoriesApi = apiSlice.injectEndpoints({ 4 | endpoints: (builder) => ({ 5 | getCategories: builder.query({ 6 | query: () => "/categories", 7 | }), 8 | }), 9 | }); 10 | 11 | export default categoriesApi; 12 | export const { useGetCategoriesQuery } = categoriesApi; 13 | -------------------------------------------------------------------------------- /src/components/Shared/Navbar/SubNavbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SubNavbar = () => { 4 | return ( 5 |
6 |
7 | 8 |
9 |
10 | ); 11 | }; 12 | 13 | export default SubNavbar; -------------------------------------------------------------------------------- /src/components/Shared/Loading/LoadingSpinner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const LoadingSpinner = () => { 4 | return ( 5 |
6 |
7 |
8 |
9 | ); 10 | }; 11 | 12 | export default LoadingSpinner; 13 | -------------------------------------------------------------------------------- /src/redux/features/product/productApi.js: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | const productApi = apiSlice.injectEndpoints({ 4 | endpoints: (builder) => ({ 5 | getProducts: builder.query({ 6 | query: () => "/products", 7 | }), 8 | getProductById: builder.query({ 9 | query: (id) => `/products/${id}`, 10 | }), 11 | }), 12 | }); 13 | 14 | export default productApi; 15 | export const { useGetProductsQuery } = productApi; 16 | -------------------------------------------------------------------------------- /src/components/ImageBB/imageUpload.jsx: -------------------------------------------------------------------------------- 1 | export const PostImage =async (image) => { 2 | const formData = new FormData(); 3 | formData.append("image", image); 4 | 5 | const url = 6 | `https://api.imgbb.com/1/upload?key=66a8afb5774f60c0f148db65634f7f62`; 7 | const res = await fetch(url, { 8 | method: "POST", 9 | body: formData, 10 | }) 11 | const data = await res.json(); 12 | // console.log(data); 13 | const imageUrl = data.data.display_url 14 | return imageUrl; 15 | } -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import Banner from "@/components/Banner/Banner"; 2 | import ChooseUs from "@/components/ChooseUs/ChooseUs"; 3 | import FeedbackForm from "@/components/FeedbackForm/FeedbackForm"; 4 | import ProductFeed from "@/components/Product/ProductFeed"; 5 | 6 | export default function Home({ products, categories }) { 7 | 8 | return ( 9 | <> 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/redux/Slice/userSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const initialState = { 4 | user: null, 5 | }; 6 | 7 | const userSlice = createSlice({ 8 | name: "user", 9 | initialState, 10 | reducers: { 11 | setUser: (state, action) => { 12 | state.user = JSON.stringify(action.payload); 13 | }, 14 | clearUser: (state) => { 15 | state.user = null; 16 | }, 17 | }, 18 | }); 19 | 20 | export const { setUser, clearUser } = userSlice.actions; 21 | export default userSlice.reducer; 22 | 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | # gitignore 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | .vercel 38 | -------------------------------------------------------------------------------- /src/redux/app/store.js: -------------------------------------------------------------------------------- 1 | 2 | import { configureStore } from "@reduxjs/toolkit";; 3 | import authReducer from "../Slice/authSlice"; 4 | import { setupListeners } from "@reduxjs/toolkit/dist/query"; 5 | import { apiSlice } from "../features/api/apiSlice"; 6 | 7 | export const store = configureStore({ 8 | reducer: { 9 | [apiSlice.reducerPath]: apiSlice.reducer, 10 | auth: authReducer, 11 | }, 12 | middleware: (getDefaultMiddleware) => 13 | getDefaultMiddleware().concat(apiSlice.middleware), 14 | devTools: true, 15 | }); 16 | setupListeners(store.dispatch); -------------------------------------------------------------------------------- /src/components/Shared/Loader/Loader.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Loader = () => { 4 | return ( 5 |
9 | 10 | Loading... 11 | 12 |
13 | ); 14 | }; 15 | 16 | export default Loader; -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/redux/store/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import { apiSlice } from "../EndPoints/fetchbasequery"; 3 | import { setupListeners } from "@reduxjs/toolkit/dist/query"; 4 | import authReducer from "../Slice/authSlice"; 5 | import useReducer from "../Slice/userSlice"; 6 | 7 | export const store = configureStore({ 8 | reducer: { 9 | [apiSlice.reducerPath]: apiSlice.reducer, 10 | auth: authReducer, 11 | user: useReducer 12 | }, 13 | middleware: (getDefaultMiddleware) => 14 | getDefaultMiddleware().concat(apiSlice.middleware), 15 | }); 16 | 17 | setupListeners(store.dispatch); 18 | 19 | -------------------------------------------------------------------------------- /public/img/social/linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/img/social/email.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/pages/products/order/index.js: -------------------------------------------------------------------------------- 1 | import Order from '@/components/Product/Order'; 2 | import { useGetOrderProductQuery } from '@/redux/features/addToCard/addToCard'; 3 | import React from 'react'; 4 | 5 | const Index = () => { 6 | const {data, isLoading, isError} = useGetOrderProductQuery() 7 | console.log(data); 8 | return ( 9 |
10 |
11 | { 12 | data?.data.map((data, i)=> <> 13 | 14 | ) 15 | } 16 |
17 |
18 | ); 19 | }; 20 | 21 | export default Index; -------------------------------------------------------------------------------- /src/pages/_app.js: -------------------------------------------------------------------------------- 1 | import Layout from "@/components/Layout/Layout"; 2 | import { store, wrapper } from "@/redux/app/store"; 3 | import { SessionProvider } from "next-auth/react"; 4 | import { Provider } from "react-redux"; 5 | import "@/styles/globals.css"; 6 | import { Toaster } from "react-hot-toast"; 7 | 8 | export default function App({ 9 | Component, 10 | pageProps: { session, ...pageProps }, 11 | }) { 12 | return ( 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/redux/features/userFeedBack/FeedBack.js: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | 4 | const featherAPI = apiSlice.injectEndpoints({ 5 | endpoints: (builder) => ({ 6 | addFeedBack: builder.mutation({ 7 | query: (formData) => { 8 | return { 9 | url: `/api/v1/feedback/send-feedback`, 10 | method: "POST", 11 | body: formData, 12 | }; 13 | }, 14 | }), 15 | getFeedBack: builder.query({ 16 | query: () => { 17 | return { 18 | url: `/api/v1/feather/get-feather`, 19 | method: "GET", 20 | }; 21 | }, 22 | }) 23 | }), 24 | }); 25 | 26 | export const { 27 | useAddFeedBackMutation, 28 | useGetFeedBackQuery 29 | } = featherAPI; -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 5 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 7 | ], 8 | theme: { 9 | fontFamily: { 10 | Poppins: ["Poppins", "sans-serif"], 11 | }, 12 | extend: { 13 | colors: { 14 | blue: { 15 | light: "#0a81ab", 16 | dark: "#0c4271", 17 | }, 18 | }, 19 | }, 20 | screens: { 21 | xxs: "375px", 22 | xs: "425px", 23 | sm: "640px", 24 | md: "780px", 25 | lg: "1024px", 26 | xl: "1280px", 27 | "2xl": "1536px", 28 | }, 29 | }, 30 | plugins: [require("@tailwindcss/line-clamp")], 31 | }; 32 | 33 | // Tailwind -------------------------------------------------------------------------------- /src/redux/features/productFeather/productFeather.js: -------------------------------------------------------------------------------- 1 | // import { apiSlice } from "../api/apiSlice"; 2 | 3 | import { apiSlice } from "../api/apiSlice"; 4 | 5 | 6 | const featherAPI = apiSlice.injectEndpoints({ 7 | endpoints: (builder) => ({ 8 | addFeather: builder.mutation({ 9 | query: (formData) => { 10 | return { 11 | url: `/api/v1/feather/create-feater`, 12 | method: "POST", 13 | body: formData, 14 | }; 15 | }, 16 | }), 17 | getFeather: builder.query({ 18 | query: () => { 19 | return { 20 | url: `/api/v1/feather/get-feather`, 21 | method: "GET", 22 | }; 23 | }, 24 | }), 25 | }), 26 | }); 27 | 28 | export const { 29 | useAddFeatherMutation, 30 | useGetFeatherQuery 31 | } = featherAPI; -------------------------------------------------------------------------------- /src/constants/constants.js: -------------------------------------------------------------------------------- 1 | export const NavbarDropdown = [ 2 | { 3 | id: 5, 4 | name: "Logout", 5 | }, 6 | ]; 7 | 8 | export const NavbarCategories = [ 9 | { 10 | id: 1, 11 | name: "CPU / Processor", 12 | path: "/categories/processor", 13 | }, 14 | { 15 | id: 2, 16 | name: "Motherboard", 17 | path: "/categories/motherboard", 18 | }, 19 | { 20 | id: 3, 21 | name: "RAM", 22 | path: "/categories/RAM", 23 | }, 24 | { 25 | id: 4, 26 | name: "Power Supply Unit", 27 | path: "/categories/Power Supply Unit", 28 | }, 29 | { 30 | id: 5, 31 | name: "Storage Device", 32 | path: "/categories/Storage Device", 33 | }, 34 | { 35 | id: 6, 36 | name: "Monitor", 37 | path: "/categories/monitor", 38 | }, 39 | { 40 | id: 7, 41 | name: "Others", 42 | path: "/categories/others", 43 | }, 44 | ]; 45 | -------------------------------------------------------------------------------- /src/pages/add-to-cart/index.js: -------------------------------------------------------------------------------- 1 | import Card from '@/components/Shared/AddToCart/Card'; 2 | import { useGetAddToCartProductsQuery } from '@/redux/features/addToCard/addToCard'; 3 | import { useRouter } from 'next/router'; 4 | import React, { useEffect } from 'react'; 5 | 6 | const Index = () => { 7 | const router = useRouter() 8 | const {data, isLoading, isError, refetch} = useGetAddToCartProductsQuery() 9 | useEffect(() => { 10 | if (typeof window !== "undefined") { 11 | const accessToken = localStorage.getItem("accessToken"); 12 | const refreshToken = localStorage.getItem("refreshToken"); 13 | if (!accessToken && !refreshToken) { 14 | router.push('/sign-in'); 15 | } 16 | } 17 | }, [router]); 18 | return ( 19 |
20 | 21 |
22 | ); 23 | }; 24 | 25 | export default Index; -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | // pages/404.js 2 | import Head from "next/head"; 3 | import Link from "next/link"; 4 | 5 | export default function Custom404() { 6 | return ( 7 | <> 8 | 9 | PC Builder | Page Not Found 10 | 11 | 12 |
13 |
14 |
15 |

16 | 404 17 |

18 |

19 | Page Not Found 20 |

21 |
22 | 23 | HomePage 24 | 25 |
26 |
27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /src/components/Shared/Navbar/Navbar.js: -------------------------------------------------------------------------------- 1 | import { ChevronDownIcon } from "@heroicons/react/24/solid"; 2 | import Image from "next/image"; 3 | import { useRouter } from "next/router"; 4 | import { useState } from "react"; 5 | import Skeleton from "react-loading-skeleton"; 6 | import Dropdown from "../../UI/Dropdown"; 7 | 8 | import { NavbarCategories, NavbarDropdown } from "@/constants/constants"; 9 | import { signIn, useSession } from "next-auth/react"; 10 | import Link from "next/link"; 11 | import MainNavbar from "./MainNavbar"; 12 | import SubNavbar from "./SubNavbar"; 13 | 14 | function Navbar() { 15 | const router = useRouter(); 16 | const [dropDown, setDropDown] = useState(false); 17 | const [categoriesDropDown, setCategoriesDropDown] = useState(false); 18 | const { data: session, status } = useSession(); 19 | const userImage = session?.user?.image || "/img/profile_pic.svg"; 20 | 21 | return ( 22 |
23 | 24 | 25 |
26 | ); 27 | } 28 | 29 | export default Navbar; 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pc-builder-assignment", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "react-scripts start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@heroicons/react": "^2.0.18", 13 | "@reduxjs/toolkit": "^1.9.5", 14 | "@tailwindcss/line-clamp": "^0.4.4", 15 | "autoprefixer": "10.4.14", 16 | "axios": "^1.5.1", 17 | "eslint": "8.45.0", 18 | "eslint-config-next": "13.4.12", 19 | "js-cookie": "^3.0.5", 20 | "next": "13.4.12", 21 | "next-auth": "^4.22.3", 22 | "next-redux-wrapper": "^8.1.0", 23 | "postcss": "8.4.27", 24 | "react": "18.2.0", 25 | "react-dom": "18.2.0", 26 | "react-hot-toast": "^2.4.1", 27 | "react-icon": "^1.0.0", 28 | "react-icons": "^4.11.0", 29 | "react-loader-spinner": "^5.3.4", 30 | "react-loading-skeleton": "^3.3.1", 31 | "react-onclickoutside": "^6.13.0", 32 | "react-redux": "^8.1.1", 33 | "tailwindcss": "3.3.3" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/pages/product/[productId].js: -------------------------------------------------------------------------------- 1 | import Card from "@/components/Shared/SingleCard/Card"; 2 | 3 | const ProductDetails = ({ item }) => { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | }; 10 | 11 | export default ProductDetails; 12 | 13 | export const getStaticPaths = async () => { 14 | const res = await fetch(`https://gadget-galaxy-server-seven.vercel.app/api/v1/product/get-product`) 15 | 16 | 17 | const datas = await res?.json() 18 | const data = datas?.data 19 | const paths = data?.map((pro) => ({ 20 | params: { productId: pro._id } 21 | 22 | })) 23 | return { paths, fallback: false } 24 | } 25 | 26 | export const getStaticProps = async (context) => { 27 | const { params } = context 28 | const res = await fetch(`https://gadget-galaxy-server-seven.vercel.app/api/v1/product/get-product/${params.productId}`) 29 | 30 | const data = await res?.json() 31 | return { 32 | props: { 33 | item: data 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/FeedbackForm/FeedbackForm.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import React from 'react'; 3 | import FeedFrom from './FeedFrom'; 4 | // FeedbackFrom 5 | const FeedbackForm = () => { 6 | return ( 7 |
8 |
9 | Feedback Form 10 |

Please provide a brief description of your feedback

11 |
12 |
13 |
14 | feedback image 19 |
20 |
21 | 22 |
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default FeedbackForm; -------------------------------------------------------------------------------- /src/pages/products/printer/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | return ( 20 |
21 | {isLoading ? :
22 | { 23 | data?.data?.map((item) => <> 24 | 25 | ) 26 | } 27 |
} 28 | 29 |
30 | ); 31 | }; 32 | 33 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/vr/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | 20 | return ( 21 |
22 | {isLoading ? :
23 | { 24 | data?.data?.map((item) => <> 25 | 26 | ) 27 | } 28 |
} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/view-all-products/index.jsx: -------------------------------------------------------------------------------- 1 | import ViewCart from '@/components/Shared/Card/ViewCart'; 2 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 3 | import { useDeleteToProductMutation, useGetAllProductQuery } from '@/redux/features/productFeather/products'; 4 | import React from 'react'; 5 | import toast from 'react-hot-toast'; 6 | 7 | const Index = () => { 8 | const { data, isLoading, refetch } = useGetAllProductQuery(); 9 | const [deleteToCart, resInfo] = useDeleteToProductMutation() 10 | 11 | const deleteToCartItem = async (id) => { 12 | await deleteToCart(id) 13 | await refetch() 14 | toast.error("Yah..! Delete successfully"); 15 | } 16 | return ( 17 |
18 | {isLoading ? :
19 | { 20 | data.data?.map((item) => <> 21 | 22 | ) 23 | } 24 |
} 25 | 26 |
27 | ); 28 | }; 29 | 30 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/laptop-battery/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | 20 | return ( 21 |
22 | {isLoading ? :
23 | { 24 | data?.data?.map((item) => <> 25 | 26 | ) 27 | } 28 |
} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/smart-watch/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | 20 | return ( 21 |
22 | {isLoading ? :
23 | { 24 | data?.data?.map((item) => <> 25 | 26 | ) 27 | } 28 |
} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/television-startech/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | 20 | return ( 21 |
22 | {isLoading ? :
23 | { 24 | data?.data?.map((item) => <> 25 | 26 | ) 27 | } 28 |
} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/mobile-phone/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | 20 | 21 | 22 | return ( 23 |
24 | {isLoading ? :
25 | { 26 | data?.data?.map((item) => <> 27 | 28 | ) 29 | } 30 |
} 31 | 32 |
33 | ); 34 | }; 35 | 36 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/portable-power-station/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect, useState } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | 6 | const Index = () => { 7 | 8 | const [routePath, setRoutePath] = useState() 9 | 10 | useEffect(() => { 11 | const pathSegments = window.location.pathname.split('/'); 12 | const lastSegment = pathSegments[pathSegments.length - 1]; 13 | setRoutePath(lastSegment); 14 | }, []); 15 | 16 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 17 | feather: routePath 18 | }) 19 | 20 | return ( 21 |
22 | {isLoading ? :
23 | { 24 | data?.data?.map((item) => <> 25 | 26 | ) 27 | } 28 |
} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/laptop/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React, { useEffect } from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | 7 | const Index = () => { 8 | 9 | const [routePath, setRoutePath] = useState() 10 | 11 | useEffect(() => { 12 | const pathSegments = window.location.pathname.split('/'); 13 | const lastSegment = pathSegments[pathSegments.length - 1]; 14 | setRoutePath(lastSegment); 15 | }, []); 16 | 17 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 18 | feather: routePath 19 | }) 20 | 21 | return ( 22 |
23 | {isLoading ? :
24 | { 25 | data?.data?.map((item) => <> 26 | 27 | ) 28 | } 29 |
} 30 | 31 |
32 | ); 33 | }; 34 | 35 | export default Index; -------------------------------------------------------------------------------- /src/components/Categories/CategoriesProduct.js: -------------------------------------------------------------------------------- 1 | import Product from "../Product/Product"; 2 | // Catagories Product 3 | function CategoriesProduct({ products, categoryName }) { 4 | return ( 5 |
6 |

7 | {categoryName} 8 |

9 |
10 | {products?.map( 11 | ({ 12 | id, 13 | productName, 14 | price, 15 | description, 16 | category, 17 | image, 18 | status, 19 | reviews, 20 | }) => ( 21 | 32 | ) 33 | )} 34 |
35 |
36 | ); 37 | } 38 | 39 | export default CategoriesProduct; 40 | -------------------------------------------------------------------------------- /src/pages/products/earbuds/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | const [routePath, setRoutePath] = useState() 10 | 11 | useEffect(() => { 12 | const pathSegments = window.location.pathname.split('/'); 13 | const lastSegment = pathSegments[pathSegments.length - 1]; 14 | setRoutePath(lastSegment); 15 | }, []); 16 | 17 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 18 | feather: routePath 19 | }) 20 | return ( 21 |
22 | {isLoading ? :
23 | { 24 | data?.data?.map((item) => <> 25 | 26 | ) 27 | } 28 |
} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/gimbal/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useEffect } from 'react'; 6 | import { useState } from 'react'; 7 | 8 | const Index = () => { 9 | const [routePath, setRoutePath] = useState() 10 | 11 | useEffect(() => { 12 | const pathSegments = window.location.pathname.split('/'); 13 | const lastSegment = pathSegments[pathSegments.length - 1]; 14 | setRoutePath(lastSegment); 15 | }, []); 16 | 17 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 18 | feather: routePath 19 | }) 20 | 21 | return ( 22 |
23 | {isLoading ? :
24 | { 25 | data?.data?.map((item) => <> 26 | 27 | ) 28 | } 29 |
} 30 | 31 |
32 | ); 33 | }; 34 | 35 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/drone/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: 'drone' 20 | }) 21 | 22 | return ( 23 |
24 | {isLoading ? :
25 | { 26 | data?.data?.map((item) => <> 27 | 28 | ) 29 | } 30 |
} 31 | 32 |
33 | ); 34 | }; 35 | 36 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/headphone/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: routePath 20 | }) 21 | return ( 22 |
23 | {isLoading ? :
24 | { 25 | data?.data?.map((item) => <> 26 | 27 | ) 28 | } 29 |
} 30 | 31 |
32 | ); 33 | }; 34 | 35 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/cc-camera/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: routePath 20 | }) 21 | 22 | return ( 23 |
24 | {isLoading ? :
25 | { 26 | data?.data?.map((item) => <> 27 | 28 | ) 29 | } 30 |
} 31 | 32 |
33 | ); 34 | }; 35 | 36 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/graphics-card/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: routePath 20 | }) 21 | return ( 22 |
23 | {isLoading ? :
24 | { 25 | data?.data?.map((item) => <> 26 | 27 | ) 28 | } 29 |
} 30 | 31 |
32 | ); 33 | }; 34 | 35 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/action-camera/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: routePath 20 | }) 21 | 22 | return ( 23 |
24 | {isLoading ? :
25 | { 26 | data?.data?.map((item) => <> 27 | 28 | ) 29 | } 30 |
} 31 | 32 |
33 | ); 34 | }; 35 | 36 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/gaming-console/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: routePath 20 | }) 21 | 22 | return ( 23 |
24 | {isLoading ? :
25 | { 26 | data?.data?.map((item) => <> 27 | 28 | ) 29 | } 30 |
} 31 | 32 |
33 | ); 34 | }; 35 | 36 | export default Index; -------------------------------------------------------------------------------- /src/pages/products/bluetooth-speakers/index.jsx: -------------------------------------------------------------------------------- 1 | import { useGetFeatherProductQuery } from '@/redux/features/productFeather/products'; 2 | import React from 'react'; 3 | import Card from '@/components/Shared/Card/Card'; 4 | import LoadingSpinner from '@/components/Shared/Loading/LoadingSpinner'; 5 | import { useState } from 'react'; 6 | import { useEffect } from 'react'; 7 | 8 | const Index = () => { 9 | 10 | const [routePath, setRoutePath] = useState() 11 | 12 | useEffect(() => { 13 | const pathSegments = window.location.pathname.split('/'); 14 | const lastSegment = pathSegments[pathSegments.length - 1]; 15 | setRoutePath(lastSegment); 16 | }, []); 17 | 18 | const { data, isLoading, refetch } = useGetFeatherProductQuery({ 19 | feather: routePath 20 | }) 21 | 22 | return ( 23 |
24 | {isLoading ? :
25 | { 26 | data?.data?.map((item) => <> 27 | 28 | ) 29 | } 30 |
} 31 | 32 |
33 | ); 34 | }; 35 | 36 | export default Index; -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/UI/Dropdown.js: -------------------------------------------------------------------------------- 1 | import { signOut } from "next-auth/react"; 2 | import { useRouter } from "next/router"; 3 | import onClickOutside from "react-onclickoutside"; 4 | 5 | function Dropdown({ hideDropDown, DropdownItem }) { 6 | const router = useRouter(); 7 | Dropdown.handleClickOutside = hideDropDown; 8 | 9 | return ( 10 |
11 | {DropdownItem.map((item) => { 12 | if (item.name === "Logout") { 13 | return ( 14 |
{ 18 | signOut(); 19 | }} 20 | > 21 | Logout 22 |
23 | ); 24 | } 25 | 26 | return ( 27 |
router.push(`/${item.path}`)} 31 | > 32 | {item.name} 33 |
34 | ); 35 | })} 36 |
37 | ); 38 | } 39 | 40 | const clickOutsideConfig = { 41 | handleClickOutside: () => Dropdown.handleClickOutside, 42 | }; 43 | 44 | export default onClickOutside(Dropdown, clickOutsideConfig); 45 | -------------------------------------------------------------------------------- /src/redux/Slice/authSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | import Cookies from "js-cookie"; 3 | const isBrowser = typeof window !== "undefined"; 4 | const accessToken = isBrowser ? localStorage.getItem("accessToken") : null; 5 | const refreshToken = isBrowser ? localStorage.getItem("refreshToken") : null; 6 | let initialState = { 7 | accessToken: null, 8 | refreshToken: null, 9 | }; 10 | if (accessToken && refreshToken) { 11 | initialState.accessToken = accessToken; 12 | initialState.refreshToken = refreshToken; 13 | } 14 | const authSlice = createSlice({ 15 | name: "auth", 16 | initialState, 17 | reducers: { 18 | setCredentials: (state, action) => { 19 | const { accessToken, refreshToken, user } = action.payload; 20 | state.accessToken = accessToken; 21 | state.refreshToken = refreshToken; 22 | state.user = refreshToken; 23 | localStorage.setItem("accessToken", accessToken); 24 | localStorage.setItem("refreshToken", refreshToken); 25 | localStorage.setItem("user", user); 26 | }, 27 | logOut: (state, action) => { 28 | state.accessToken = null; 29 | state.refreshToken = null; 30 | localStorage.removeItem("accessToken"); 31 | localStorage.removeItem("refreshToken"); 32 | localStorage.removeItem("user", data.user); 33 | Cookies.remove("sessionid"); 34 | }, 35 | }, 36 | }); 37 | export default authSlice.reducer; 38 | export const { setCredentials, logOut } = authSlice.actions; 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/redux/features/productFeather/products.js: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | 4 | const featherAPI = apiSlice.injectEndpoints({ 5 | endpoints: (builder) => ({ 6 | addProducts: builder.mutation({ 7 | query: (formData) => { 8 | return { 9 | url: `/api/v1/product/create-product`, 10 | method: "POST", 11 | body: formData, 12 | }; 13 | }, 14 | }), 15 | getProducts: builder.query({ 16 | query: () => { 17 | return { 18 | url: `/api/v1/feather/get-feather`, 19 | method: "GET", 20 | }; 21 | }, 22 | }), 23 | getFeatherProduct: builder.query({ 24 | query: ({feather}) => { 25 | return { 26 | url: `/api/v1/product/get-feather-product?feather=${feather}`, 27 | method: "GET", 28 | }; 29 | }, 30 | }), 31 | getAllProduct: builder.query({ 32 | query: () => { 33 | return { 34 | url: `/api/v1/product/get-product`, 35 | method: "GET", 36 | }; 37 | }, 38 | }), 39 | deleteToProduct: builder.mutation({ 40 | query: (id) => ({ 41 | url: `/api/v1/product/delete-product/${id}`, 42 | method: "DELETE", 43 | }), 44 | }), 45 | }), 46 | }); 47 | 48 | export const { 49 | useAddProductsMutation, 50 | useGetFeatherProductQuery, 51 | useGetAllProductQuery, 52 | useDeleteToProductMutation 53 | } = featherAPI; -------------------------------------------------------------------------------- /src/components/Product/ViewOrderProduct.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const ViewOrderProduct = ({ setViewOrderPage, item }) => { 4 | return ( 5 |
6 |
7 |
8 |
9 |
10 |
11 |

{item.name}

12 |
13 |
14 | {item?.img} 21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 | ); 30 | }; 31 | 32 | export default ViewOrderProduct; -------------------------------------------------------------------------------- /src/components/Shared/Card/HomePageCard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useRouter } from 'next/router'; 3 | 4 | const HomePageCard = ({ item }) => { 5 | const router = useRouter(); 6 | const productDetails = (id) => { 7 | router.push(`/product/${id}`); 8 | }; 9 | 10 | return ( 11 |
12 |
13 |
14 | 23 |
24 |
25 |

26 | 29 |

30 |
31 |
32 |
33 | ${item?.price} 34 |
35 |
36 | ); 37 | }; 38 | 39 | export default HomePageCard; 40 | -------------------------------------------------------------------------------- /src/components/Categories/Categories.js: -------------------------------------------------------------------------------- 1 | import { useGetFeatherQuery } from "@/redux/features/productFeather/productFeather"; 2 | import { useRouter } from "next/router"; 3 | import React from "react"; 4 | // Catagoris 5 | const Categories = () => { 6 | const router = useRouter() 7 | const { data: productFeather, isLoading, isError } = useGetFeatherQuery() 8 | const opneProduct = (item)=>{ 9 | router.push(`products/${item.dis}`); 10 | } 11 | return ( 12 |
13 |
14 |

15 | Featured Category 16 |

17 |

Get Your Desired Product from Featured Category!

18 |
19 | 20 |
21 |
22 | {productFeather?.data?.map((item, i) => ( 23 | 35 | ))} 36 |
37 |
38 | 39 |
40 | ); 41 | }; 42 | 43 | export default Categories; 44 | -------------------------------------------------------------------------------- /src/pages/categories/[categoryName].js: -------------------------------------------------------------------------------- 1 | // import CategoriesProduct from "@/components/Categories/CategoriesProduct"; 2 | // import { capitalizeFirstLetter } from "@/utils/capitalizeFirstLetter"; 3 | // import React from "react"; 4 | 5 | // const Category = ({ products, categoryName }) => { 6 | // return ( 7 | //
0 ? "" : "h-screen"}`}> 8 | // 9 | //
10 | // ); 11 | // }; 12 | 13 | // export default Category; 14 | 15 | // export const getStaticPaths = async () => { 16 | // const res = await fetch( 17 | // "https://pc-builder-assignment-server.vercel.app/products" 18 | // ); 19 | // const products = await res.json(); 20 | // const paths = products.map((product) => ({ 21 | // params: { categoryName: product.category }, 22 | // })); 23 | // return { 24 | // paths, 25 | // fallback: true, 26 | // }; 27 | // }; 28 | 29 | // export const getStaticProps = async (context) => { 30 | 31 | 32 | // try { 33 | // const res = await fetch( 34 | // `https://pc-builder-assignment-server.vercel.app/products?category=${capitalizeFirstLetter( 35 | // context.params.categoryName 36 | // )}` 37 | // ); 38 | // const products = await res.json(); 39 | 40 | // return { 41 | // props: { 42 | // products, 43 | // categoryName: context.params.categoryName, 44 | // }, 45 | // }; 46 | // } catch (error) { 47 | // console.log(error); 48 | // return { 49 | // notFound: true, 50 | // }; 51 | // } 52 | // }; 53 | 54 | import React from 'react'; 55 | 56 | const Index = () => { 57 | return ( 58 |
59 | 60 |
61 | ); 62 | }; 63 | 64 | export default Index; -------------------------------------------------------------------------------- /src/pages/product-details/[productId].js: -------------------------------------------------------------------------------- 1 | import ProductDetails from "@/components/Product/ProductDetails"; 2 | import Head from "next/head"; 3 | 4 | const ProductInfo = ({ product }) => { 5 | return ( 6 | <> 7 | {product?.productName && ( 8 | 9 | PC Builder | {product?.productName} 10 | 11 | )} 12 | 25 | 26 | ); 27 | }; 28 | 29 | export default ProductInfo; 30 | 31 | export const getStaticPaths = async () => { 32 | const res = await fetch( 33 | "https://pc-builder-assignment-server.vercel.app/products" 34 | ); 35 | const products = await res.json(); 36 | const paths = products.map((product) => ({ 37 | params: { productId: product.id.toString() }, 38 | })); 39 | 40 | return { 41 | paths, 42 | fallback: true, 43 | }; 44 | }; 45 | 46 | export const getStaticProps = async (context) => { 47 | try { 48 | const res = await fetch( 49 | `https://pc-builder-assignment-server.vercel.app/products/${context.params.productId}` 50 | ); 51 | const product = await res.json(); 52 | 53 | return { 54 | props: { 55 | product, 56 | }, 57 | }; 58 | } catch (error) { 59 | console.log(error); 60 | return { 61 | notFound: true, 62 | }; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /src/redux/features/api/apiSlice.js: -------------------------------------------------------------------------------- 1 | import { HYDRATE } from "next-redux-wrapper"; 2 | 3 | 4 | import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; 5 | import axios from "axios"; 6 | import { logOut, setCredentials } from "../../Slice/authSlice"; 7 | const URL = "https://gadget-galaxy-server-seven.vercel.app"; 8 | // const URL = "http://localhost:5000/"; 9 | 10 | const baseQuery = fetchBaseQuery({ 11 | baseUrl: URL, 12 | prepareHeaders: (headers, { getState }) => { 13 | const token = getState().auth.accessToken; 14 | if (token) { 15 | headers.set("authorization", `Bearer ${token}`); 16 | } 17 | return headers; 18 | }, 19 | }); 20 | 21 | const baseQueryWithRefresh = async (args, api, extraOptions) => { 22 | let result = await baseQuery(args, api, extraOptions); 23 | 24 | if (result?.error?.status === 403) { 25 | const refreshToken = api.getState().auth.refreshToken; 26 | const data = { refreshToken: refreshToken }; 27 | const refreshResult = await axios.post(`${URL}/`, data); 28 | if (refreshResult?.data) { 29 | api.dispatch(setCredentials()); 30 | const accessToken = refreshResult.data.accessToken; 31 | console.log(accessToken); 32 | const refreshToken = refreshResult.data.refreshToken; 33 | console.log(refreshToken); 34 | console.log("with refresh"); 35 | result = await baseQuery(args, api, extraOptions); 36 | } else { 37 | api.dispatch(logOut()); 38 | } 39 | } 40 | return result; 41 | }; 42 | 43 | 44 | export const apiSlice = createApi({ 45 | reducerPath: "api", 46 | baseQuery: baseQueryWithRefresh, 47 | tagTypes: [ 48 | 'cart-tags' 49 | ], 50 | extractRehydrationInfo(action, { reducerPath }) { 51 | if (action.type === HYDRATE) { 52 | return action.payload[reducerPath]; 53 | } 54 | }, 55 | endpoints: () => ({}), 56 | }); 57 | -------------------------------------------------------------------------------- /public/img/social/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/Shared/Card/ViewCart.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useRouter } from 'next/router'; 3 | 4 | const ViewCart = ({ item, deleteToCartItem }) => { 5 | const router = useRouter(); 6 | const productDetails = (id) => { 7 | router.push(`/product/${id}`); 8 | }; 9 | 10 | return ( 11 |
12 |
13 |
14 | 23 |
24 |
25 |

26 | 29 |

30 |
31 |
32 |
33 | ${item?.price} 34 |
35 |
36 | 37 | {/* */} 38 |
39 |
40 | ); 41 | }; 42 | 43 | export default ViewCart; 44 | -------------------------------------------------------------------------------- /src/redux/features/addToCard/addToCard.js: -------------------------------------------------------------------------------- 1 | // import { apiSlice } from "../api/apiSlice"; 2 | 3 | import { apiSlice } from "../api/apiSlice"; 4 | 5 | 6 | const featherAPI = apiSlice.injectEndpoints({ 7 | endpoints: (builder) => ({ 8 | addToCartProduct: builder.mutation({ 9 | query: (data) => { 10 | const id = data.id; 11 | const body = data.body; 12 | return { 13 | url: `/api/v1/product/add-to-cart/${id}`, 14 | method: "POST", 15 | body, 16 | }; 17 | }, 18 | }), 19 | getAddToCartProducts: builder.query({ 20 | query: () => { 21 | return { 22 | url: `/api/v1/product/get-to-cart`, 23 | method: "GET", 24 | }; 25 | }, 26 | invalidatesTags: ["cart-tags"], 27 | }), 28 | getOrderProduct: builder.query({ 29 | query: () => { 30 | return { 31 | url: `/api/v1/product/get-all-order-products`, 32 | method: "GET", 33 | }; 34 | }, 35 | invalidatesTags: ["cart-tags"], 36 | }), 37 | deleteToCart: builder.mutation({ 38 | query: (id) => ({ 39 | url: `/api/v1/product/delete-to-cart/${id}`, 40 | method: "DELETE", 41 | }), 42 | invalidatesTags: ["cart-tags"], 43 | }), 44 | confirmProduct: builder.mutation({ 45 | query: () => { 46 | return { 47 | url: `/api/v1/product/get-order-products`, 48 | method: "POST", 49 | }; 50 | }, 51 | 52 | }), 53 | }), 54 | }); 55 | 56 | export const { 57 | useAddToCartProductMutation, 58 | useGetAddToCartProductsQuery, 59 | useDeleteToCartMutation, 60 | useConfirmProductMutation, 61 | useGetOrderProductQuery 62 | } = featherAPI; -------------------------------------------------------------------------------- /src/components/Product/ProductFeed.js: -------------------------------------------------------------------------------- 1 | import { useGetAllProductQuery } from "@/redux/features/productFeather/products"; 2 | import Categories from "../Categories/Categories"; 3 | import LoadingSpinner from "../Shared/Loading/LoadingSpinner"; 4 | import { useEffect } from "react"; 5 | import { useState } from "react"; 6 | import HomePageCard from "../Shared/Card/HomePageCard"; 7 | function ProductFeed() { 8 | const { data, isLoading, refetch } = useGetAllProductQuery(); 9 | const [randomProducts, setRandomProducts] = useState([]); 10 | function shuffleArray(array) { 11 | const shuffledArray = [...array]; 12 | for (let i = shuffledArray.length - 1; i > 0; i--) { 13 | const j = Math.floor(Math.random() * (i + 1)); 14 | [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]]; 15 | } 16 | return shuffledArray; 17 | } 18 | 19 | useEffect(() => { 20 | if (data) { 21 | const shuffledProducts = shuffleArray(data.data).slice(0, 20); 22 | setRandomProducts(shuffledProducts); 23 | } 24 | }, [data]); 25 | 26 | return ( 27 |
28 |
29 | 30 | 31 | 32 |
33 |

34 | Featured Products 35 |

36 |

37 | Check & Get Your Desired Product! 38 |

39 |
40 | {isLoading ? :
41 | { 42 | randomProducts?.map((item) => <> 43 | 44 | ) 45 | } 46 |
} 47 | 48 |
49 |
50 |
51 |
52 | ); 53 | } 54 | 55 | export default ProductFeed; 56 | -------------------------------------------------------------------------------- /src/components/Layout/Layout.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import Navbar from "../Shared/Navbar/Navbar"; 3 | import Footer from "../Shared/Footer/Footer"; 4 | import MobileNavbar from "../Shared/Navbar/MobileNavbar"; 5 | 6 | const Layout = ({ children }) => { 7 | 8 | return ( 9 | <> 10 | 11 | 12 | 13 | 17 | Gadget Galaxy 18 | 22 | 27 | 33 | 39 | 40 | 45 | 46 | 47 | 51 | 52 | 53 |
54 | <> 55 | 56 | 57 | {children} 58 |
59 | 60 |
61 | 62 | ); 63 | } 64 | 65 | export default Layout; -------------------------------------------------------------------------------- /src/components/Product/Order.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ViewOrderProduct from './ViewOrderProduct'; 3 | import { useState } from 'react'; 4 | 5 | const Order = ({ item, i }) => { 6 | const [viewOrderPage, setViewOrderPage] = useState(false) 7 | return ( 8 |
9 |
10 |
11 |
12 |

Order# {i}

13 |

14 | Date Added: {item.created_at} 15 |

16 |
17 |
18 |

Status

19 |
20 |
21 |
22 |
23 | {item?.img} 30 |

{item?.name}

31 |
32 |
33 |

${item?.price}

34 | 35 |
36 |
37 |
38 |
39 | {viewOrderPage && } 40 |
41 |
42 | ); 43 | }; 44 | 45 | export default Order; -------------------------------------------------------------------------------- /src/redux/features/auth/userAuth.js: -------------------------------------------------------------------------------- 1 | import { apiSlice } from "../api/apiSlice"; 2 | 3 | 4 | const featherAPI = apiSlice.injectEndpoints({ 5 | endpoints: (builder) => ({ 6 | createUser: builder.mutation({ 7 | query: (data) => { 8 | return { 9 | url: `/api/v1/auth/register`, 10 | method: "POST", 11 | body: data, 12 | }; 13 | }, 14 | }), 15 | loginUser: builder.mutation({ 16 | query: (data) => { 17 | return { 18 | url: `/api/v1/auth/login`, 19 | method: "POST", 20 | body: data, 21 | }; 22 | }, 23 | }), 24 | getUserProfile: builder.query({ 25 | query: () => { 26 | return { 27 | url: `/api/v1/auth/get-user-profile`, 28 | method: "GET", 29 | }; 30 | }, 31 | }), 32 | getAllUser: builder.query({ 33 | query: () => { 34 | return { 35 | url: `/api/v1/auth/get-user`, 36 | method: "GET", 37 | }; 38 | }, 39 | }), 40 | updateProfile: builder.mutation({ 41 | query: (data) => { 42 | return { 43 | url: `/api/v1/auth/update-profile`, 44 | method: "PATCH", 45 | body: data, 46 | }; 47 | }, 48 | }), 49 | updateUserRole: builder.mutation({ 50 | query: (data) => { 51 | const id = data.id 52 | return { 53 | url: `/api/v1/auth/update-user-role/${id}`, 54 | method: "PATCH", 55 | body: data, 56 | }; 57 | }, 58 | }), 59 | deleteUser: builder.mutation({ 60 | query: (id) => ({ 61 | url: `/api/v1/auth/delete-user/${id}`, 62 | method: "DELETE", 63 | }), 64 | }), 65 | }), 66 | }); 67 | 68 | export const { 69 | useCreateUserMutation, 70 | useLoginUserMutation, 71 | useGetUserProfileQuery, 72 | useUpdateProfileMutation, 73 | useGetAllUserQuery, 74 | useUpdateUserRoleMutation, 75 | useDeleteUserMutation 76 | } = featherAPI; -------------------------------------------------------------------------------- /public/img/profile_pic.svg: -------------------------------------------------------------------------------- 1 | profile pic -------------------------------------------------------------------------------- /src/components/Banner/Banner.js: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import { ShoppingBagIcon } from "@heroicons/react/24/outline"; 3 | 4 | function Banner() { 5 | const scrollHandler = () => { 6 | window.scrollTo({ 7 | top: document.getElementById("products-feed").offsetTop - 90, 8 | behavior: "smooth", 9 | }); 10 | //window.location.href='#products-feed' 11 | }; 12 | 13 | return ( 14 |
15 |
16 |
17 |
18 |

19 | Stay Home 20 |

21 |

22 | Shop Online. 23 |

24 |
25 |

26 | Shop online from a wide range of genuine products whenever you 27 | want 24x7. 28 |

29 | 36 |
37 |
38 | 46 |
47 |
48 |
49 | ); 50 | } 51 | 52 | export default Banner; 53 | -------------------------------------------------------------------------------- /src/components/BuildProduct/BuildProduct.js: -------------------------------------------------------------------------------- 1 | import { clearComponentByCategory } from "@/redux/features/pcbuild/pcbuildSlice"; 2 | import { XMarkIcon } from "@heroicons/react/24/outline"; 3 | import Image from "next/image"; 4 | import Link from "next/link"; 5 | import { useRouter } from "next/router"; 6 | import { useDispatch } from "react-redux"; 7 | // Build Product 8 | function BuildProduct({ 9 | id, 10 | productName, 11 | price, 12 | category, 13 | image, 14 | border, 15 | }) { 16 | const router = useRouter(); 17 | const dispatch = useDispatch(); 18 | const removeItemFromBuild = () => { 19 | dispatch(clearComponentByCategory(category)); 20 | }; 21 | 22 | return ( 23 |
28 |
29 | {productName} router.push(`/product-details/${id}`)} 37 | /> 38 |
39 | 40 | {/* Middle */} 41 |
42 |

43 | {productName} 44 |

45 |

46 | {category} 47 |

48 |
49 | 50 | {/* Buttons on the right of the products */} 51 |
52 | 58 |
59 |
60 | ); 61 | } 62 | 63 | export default BuildProduct; 64 | -------------------------------------------------------------------------------- /src/components/Shared/Navbar/MobileNavbar.js: -------------------------------------------------------------------------------- 1 | // import Search from "@/components/UI/Search"; 2 | import { Bars3Icon, ComputerDesktopIcon } from "@heroicons/react/24/outline"; 3 | import { useRouter } from "next/router"; 4 | import { useState } from "react"; 5 | import SideBarMenu from "../SidebarMenu/SidebarMenu"; 6 | import { useSelector } from "react-redux"; 7 | import Link from "next/link"; 8 | 9 | function MobileNavbar() { 10 | const router = useRouter(); 11 | const [showSideBar, setShowBar] = useState(false); 12 | const pcbuild = useSelector((state) => state.pcbuild); 13 | 14 | return ( 15 | <> 16 |
17 |
18 |
19 |
20 | setShowBar(true)} /> 21 |
22 | 23 | Gadget Galaxy 24 | 25 |
26 |
router.push("/add-to-cart")} 29 | > 30 | {/* */} 31 | shopping_basket 32 |
33 | {pcbuild?.qty} 34 |
35 |
36 |
37 |
{/* */}
38 |
39 |
45 | setShowBar(false)} /> 46 |
47 | 48 | ); 49 | } 50 | 51 | export default MobileNavbar; 52 | -------------------------------------------------------------------------------- /src/components/User/DeleteUser.jsx: -------------------------------------------------------------------------------- 1 | import { useDeleteUserMutation } from '@/redux/features/auth/userAuth'; 2 | import React from 'react'; 3 | import { useEffect } from 'react'; 4 | 5 | const DeleteUser = ({ setDeleteUser, user , refetch }) => { 6 | const [deleteUser, resInfo] = useDeleteUserMutation() 7 | 8 | const deleteUserFun = () =>{ 9 | deleteUser(user?._id) 10 | } 11 | 12 | useEffect(()=> { 13 | if (resInfo?.isSuccess) { 14 | setDeleteUser(false) 15 | refetch() 16 | } 17 | },[resInfo, setDeleteUser, refetch]) 18 | 19 | return ( 20 |
21 |
22 |
23 |
24 |
25 |
26 | 27 |
28 | 29 | 37 |

38 | Are you sure! You Detele The user 39 |

40 |
41 |
42 | 43 |
44 |
45 |
46 |
47 |
48 |
49 | ); 50 | }; 51 | 52 | export default DeleteUser; -------------------------------------------------------------------------------- /src/components/Product/Product.js: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import { ShoppingCartIcon } from "@heroicons/react/24/solid"; 3 | import Link from "next/link"; 4 | import { useRouter } from "next/router"; 5 | import { StarIcon } from "@heroicons/react/24/solid"; 6 | import { useSession } from "next-auth/react"; 7 | import { useDispatch } from "react-redux"; 8 | 9 | function Product({ 10 | id, 11 | productName, 12 | price, 13 | description, 14 | category, 15 | status, 16 | image, 17 | reviews, 18 | }) { 19 | const router = useRouter(); 20 | const dispatch = useDispatch(); 21 | const { data: session } = useSession(); 22 | 23 | const addItemToBuild = () => { 24 | if (!session?.user?.email) { 25 | alert("Please Sign In to add items to your build"); 26 | router.push("/api/auth/signin"); 27 | } else { 28 | dispatch( 29 | addComponent({ 30 | id, 31 | name: productName, 32 | price, 33 | category, 34 | image, 35 | }) 36 | ); 37 | router.push("/pc-builder"); 38 | } 39 | }; 40 | 41 | return ( 42 |
43 |

44 | {category} 45 |

46 | router.push(`/product-details/${id}`)} 54 | /> 55 |

56 | {productName} 57 |

58 |

59 | {description} 60 |

61 |
62 | $ {price} 63 | {status} 64 |
65 |
66 | {...Array(reviews) 67 | .fill() 68 | .map((_, i) => ( 69 | 70 | ))} 71 |
72 | 79 |
80 | ); 81 | } 82 | 83 | export default Product; 84 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | /* ./styles/globals.css */ 2 | 3 | /* Tailwindcss */ 4 | @tailwind base; 5 | @tailwind components; 6 | @tailwind utilities; 7 | 8 | /* Fonts */ 9 | @import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400&display=swap"); 10 | 11 | /* Custom tailwind class */ 12 | @layer components { 13 | .link { 14 | @apply cursor-pointer hover:text-blue-light active:text-blue-light; 15 | } 16 | .button { 17 | @apply cursor-pointer rounded text-center p-2 text-sm text-white bg-gradient-to-b from-blue-light to-blue-dark border border-blue-light focus:outline-none focus:ring-2 focus:ring-blue-dark active:from-blue-dark; 18 | } 19 | .button-green { 20 | @apply cursor-pointer rounded text-center p-2 text-sm text-white bg-gradient-to-b from-green-500 to-green-800 border-green-500 focus:outline-none focus:ring-2 focus:ring-green-500 active:from-green-800; 21 | } 22 | .button-red { 23 | @apply cursor-pointer rounded text-center p-2 text-sm text-white bg-gradient-to-b from-red-500 to-red-800 border-red-500 focus:outline-none focus:ring-2 focus:ring-red-500 active:from-red-800; 24 | } 25 | .dropDownOption { 26 | @apply w-full cursor-pointer hover:bg-gray-100 py-2 px-3; 27 | } 28 | .dashboard-link { 29 | @apply link rounded border px-4 py-1 hover:bg-blue-light hover:text-white transition-all duration-200 text-sm; 30 | } 31 | } 32 | 33 | * { 34 | -webkit-tap-highlight-color: transparent; 35 | scroll-behavior: smooth; 36 | } 37 | 38 | html, 39 | body { 40 | font-family: "Poppins", sans-serif; 41 | -webkit-font-smoothing: antialiased; 42 | -moz-osx-font-smoothing: grayscale; 43 | color: #1f2937; 44 | scroll-behavior: smooth; 45 | background-color: white; 46 | } 47 | 48 | .heightFix, 49 | .heightFixAdmin { 50 | min-height: calc(100vh - 150px); 51 | height: 100%; 52 | } 53 | 54 | .loader svg { 55 | width: 150px; 56 | height: 150px; 57 | } 58 | 59 | /* Hide scrollbar for Chrome, Safari and Opera */ 60 | .hideScrollBar::-webkit-scrollbar { 61 | display: none; 62 | } 63 | .table_col_img { 64 | min-width: 40px; 65 | } 66 | 67 | .table_col { 68 | min-width: 120px; 69 | } 70 | 71 | /* Hide scrollbar for IE, Edge and Firefox */ 72 | .hideScrollBar { 73 | -ms-overflow-style: none; /* IE and Edge */ 74 | scrollbar-width: none; /* Firefox */ 75 | } 76 | 77 | .glassmorphism { 78 | background-color: white; 79 | background: rgba(255, 255, 255, 0.9); 80 | backdrop-filter: blur(6px); 81 | -webkit-backdrop-filter: blur(6px); 82 | } 83 | 84 | .layout { 85 | min-width: 320px; 86 | background-color: white; 87 | } 88 | .sideBarMenu { 89 | min-width: 250px; 90 | } 91 | 92 | .layout .Toastify__progress-bar--default { 93 | background: #10b981; 94 | background: linear-gradient(#10b981, #065f46) !important; 95 | } 96 | 97 | @media only screen and (max-width: 780px) { 98 | .loader svg { 99 | width: 120px; 100 | height: 120px; 101 | } 102 | } 103 | 104 | @media only screen and (max-width: 780px) { 105 | .heightFix { 106 | min-height: calc(100vh - 200px); 107 | height: 100%; 108 | } 109 | } -------------------------------------------------------------------------------- /src/components/UI/Search.js: -------------------------------------------------------------------------------- 1 | // import { SearchIcon } from "@heroicons/react/24/solid"; 2 | import { useRef, useState } from "react"; 3 | 4 | const Search = () => { 5 | const [searchTerm, setSearchTerm] = useState(""); 6 | const searchRef = useRef(null); 7 | 8 | // const closeSearch = () => { 9 | // setSearchTerm(""); 10 | // }; 11 | 12 | // useEffect(() => { 13 | // function handleClickOutside(e) { 14 | // let targetEl = e.target; 15 | // do { 16 | // if (targetEl === searchRef.current) { 17 | // return; 18 | // } 19 | // targetEl = targetEl.parentNode; 20 | // } while (targetEl); 21 | // closeSearch(); 22 | // } 23 | // window.addEventListener("click", handleClickOutside); 24 | // return () => { 25 | // window.removeEventListener("click", handleClickOutside); 26 | // }; 27 | // }, []); 28 | 29 | 30 | return ( 31 |
32 |
33 | {/* */} 34 |
35 | setSearchTerm(e.target.value)} 41 | // onChange={searchProduct} 42 | /> 43 | 44 | {/* {searchTerm ? ( 45 |
46 | {!isLoading || !loading ? ( 47 | searchResults?.length ? ( 48 | searchResults.map(({ item: { _id, title, image } }, i) => 49 |
{ 51 | closeSearch(); 52 | router.push(`/product-details/${_id}`); 53 | }} 54 | className={`flex cursor-pointer items-center justify-between lg:px-5 py-2 px-4 ${ 55 | i !== searchResults.length 56 | ? "border-b border-gray-200" 57 | : "" 58 | } bg-gray-50 hover:bg-gray-100`} 59 | > 60 |
61 | {title} 62 |
63 |
64 | 71 |
72 |
73 | )) 74 | ) : ( 75 |

76 | No product found 77 |

78 | ) 79 | ) : ( 80 |

Loading...

81 | )} 82 |
83 | ) : ( 84 | <> 85 | )} */} 86 |
87 | ); 88 | } 89 | 90 | export default Search; 91 | -------------------------------------------------------------------------------- /src/components/Shared/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Image from "next/image"; 3 | import { useRouter } from "next/router"; 4 | import { HeartIcon } from "@heroicons/react/24/outline"; 5 | 6 | function Footer() { 7 | const router = useRouter(); 8 | const gmailHandler = () => { 9 | window.open( 10 | "mailto:" + 11 | "hazrataliein@gmail.com" + 12 | "?subject=" + 13 | " " + 14 | "&body=" + 15 | " ", 16 | "_self" 17 | ); 18 | }; 19 | return ( 20 |
21 |
22 |
23 |
24 | 25 | 26 | blob-3-removebg-preview 27 | 28 | 29 | {/* {!admin ? ( 30 | 31 | Orders 32 | 33 | ) : ( 34 | <> 35 | )} */} 36 |
37 |
38 |
39 | email 49 |
50 |
51 | linkedin { 60 | window.open("https://www.linkedin.com/in/hazratali9"); 61 | }} 62 | /> 63 |
64 |
65 | github window.open("https://www.linkedin.com/in/hazratali9")} 74 | /> 75 |
76 |
77 |
78 |

79 | Made With by 80 | 81 | Hazrat Ali 82 | 83 |

84 |
85 |
86 | ); 87 | } 88 | 89 | export default Footer; 90 | -------------------------------------------------------------------------------- /src/components/User/RoleChangeModal.jsx: -------------------------------------------------------------------------------- 1 | import { useUpdateUserRoleMutation } from '@/redux/features/auth/userAuth'; 2 | import React, { useState } from 'react'; 3 | import { useEffect } from 'react'; 4 | 5 | const RoleChangeModal = ({ setUserRoleChange , user, refetch}) => { 6 | const [updateUserRole, resInfo] = useUpdateUserRoleMutation() 7 | const [selectedRole, setSelectedRole] = useState(user?.role); 8 | 9 | const handleRoleChange = (e) => { 10 | setSelectedRole(e.target.value); 11 | }; 12 | const handleUserRoleChangeFn = ()=>{ 13 | updateUserRole({ 14 | role: selectedRole.toString(), 15 | id: user?._id 16 | }) 17 | 18 | } 19 | useEffect(()=> { 20 | if (resInfo?.isSuccess) { 21 | setUserRoleChange(false) 22 | refetch() 23 | } 24 | },[resInfo, setUserRoleChange, refetch]) 25 | return ( 26 |
27 |
28 |
29 |
30 |
31 |
32 | 33 |
34 | 35 | 43 |

44 | Are you sure! You Change the user Role 45 |

46 |
47 |
48 |
49 | 50 | 58 |
59 | 60 |
61 |
62 |
63 |
64 |
65 |
66 | ); 67 | }; 68 | 69 | export default RoleChangeModal; -------------------------------------------------------------------------------- /src/components/Shared/SingleCard/Card.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import KeyFeatures from './KeyFeatures'; 3 | import { useRouter } from 'next/router'; 4 | import { useState } from 'react'; 5 | import { useEffect } from 'react'; 6 | import { useAddToCartProductMutation } from '@/redux/features/addToCard/addToCard'; 7 | import { toast } from 'react-hot-toast'; 8 | import Loader from '../Loader/Loader'; 9 | 10 | const Card = ({ item }) => { 11 | const router = useRouter(); 12 | const [user, setUser] = useState(false); 13 | const [addToCartProduct, resInfo] = useAddToCartProductMutation() 14 | useEffect(() => { 15 | if (typeof window !== "undefined") { 16 | const user = localStorage.getItem("user"); 17 | setUser(user) 18 | } 19 | }, [router]); 20 | const buyNowProduct = async () => { 21 | if (user) { 22 | const data = { 23 | id: item._id, 24 | quantity: 1, 25 | } 26 | await addToCartProduct(data) 27 | toast.success("The product add successfully in you cart..!"); 28 | } else { 29 | router.push('/sign-in') 30 | } 31 | } 32 | 33 | 34 | return ( 35 |
36 |
37 |
38 |
39 |
40 | {item?.image} 47 |
48 |
49 |
50 |

51 |
52 | {item?.name} 53 |
54 |

55 | 56 |
57 | {item?.keyFeatures?.map((feature, featureIndex) => ( 58 | 59 | ))} 60 |
61 |
62 | ${item?.price} 63 |
64 |
65 | {resInfo.isLoading ? : 68 | } 71 |
72 |
73 |
74 |
75 |
76 | ); 77 | }; 78 | 79 | export default Card; -------------------------------------------------------------------------------- /src/redux/features/pcbuild/pcbuildSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const initialState = { 4 | processor: { 5 | id: 0, 6 | name: "", 7 | price: 0, 8 | image: "", 9 | }, 10 | gpu: { 11 | id: 0, 12 | name: "", 13 | price: 0, 14 | image: "", 15 | }, 16 | ram: { 17 | id: 0, 18 | name: "", 19 | price: 0, 20 | image: "", 21 | }, 22 | motherboard: { 23 | id: 0, 24 | name: "", 25 | price: 0, 26 | image: "", 27 | }, 28 | storagedevice: { 29 | id: 0, 30 | name: "", 31 | price: 0, 32 | image: "", 33 | }, 34 | powersupplyunit: { 35 | id: 0, 36 | name: "", 37 | price: 0, 38 | image: "", 39 | }, 40 | monitor: { 41 | id: 0, 42 | name: "", 43 | price: 0, 44 | image: "", 45 | }, 46 | others: { 47 | id: 0, 48 | name: "", 49 | price: 0, 50 | image: "", 51 | }, 52 | total: 0, 53 | qty: 0, 54 | }; 55 | 56 | const pcbuildSlice = createSlice({ 57 | name: "pcbuild", 58 | initialState, 59 | reducers: { 60 | addComponent: (state, action) => { 61 | let { id, name, price, category, image } = action.payload; 62 | category = category?.replace(/\s+/g, ""); 63 | category = category?.toLowerCase(); 64 | // is id already in the state? 65 | if (state[category]?.id !== id) { 66 | if (state[category]?.name && state[category]?.price) { 67 | state.total -= state[category].price; 68 | state.qty -= 1; 69 | } 70 | state[category] = { id, name, price, image }; 71 | state.total += price; 72 | state.qty += 1; 73 | // 74 | } 75 | }, 76 | clearComponent: (state) => { 77 | state.processor = { 78 | id: 0, 79 | name: "", 80 | price: 0, 81 | image: "", 82 | }; 83 | state.gpu = { 84 | id: 0, 85 | name: "", 86 | price: 0, 87 | image: "", 88 | }; 89 | state.ram = { 90 | id: 0, 91 | name: "", 92 | price: 0, 93 | image: "", 94 | }; 95 | state.motherboard = { 96 | id: 0, 97 | name: "", 98 | price: 0, 99 | image: "", 100 | }; 101 | state.storagedevice = { 102 | id: 0, 103 | name: "", 104 | price: 0, 105 | image: "", 106 | }; 107 | state.powersupplyunit = { 108 | id: 0, 109 | name: "", 110 | price: 0, 111 | image: "", 112 | }; 113 | state.monitor = { 114 | id: 0, 115 | name: "", 116 | price: 0, 117 | image: "", 118 | }; 119 | state.others = { 120 | id: 0, 121 | name: "", 122 | price: 0, 123 | image: "", 124 | }; 125 | state.total = 0; 126 | state.qty = 0; 127 | }, 128 | clearComponentByCategory: (state, action) => { 129 | let category = action.payload; 130 | category = category.replace(/\s+/g, ""); 131 | category = category.toLowerCase(); 132 | state[category] = { 133 | id: 0, 134 | name: "", 135 | price: 0, 136 | image: "", 137 | }; 138 | state.total -= state[category].price; 139 | state.qty -= 1; 140 | }, 141 | }, 142 | }); 143 | 144 | export const { addComponent, clearComponent, clearComponentByCategory } = 145 | pcbuildSlice.actions; 146 | export default pcbuildSlice.reducer; 147 | -------------------------------------------------------------------------------- /src/components/Shared/Card/Card.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import KeyFeatures from './KeyFeatures'; 3 | import { useRouter } from 'next/router'; 4 | import { useAddToCartProductMutation } from '@/redux/features/addToCard/addToCard'; 5 | import { toast } from 'react-hot-toast'; 6 | import Loader from '../Loader/Loader'; 7 | 8 | const Card = ({ item }) => { 9 | const router = useRouter(); 10 | const [user, setUser] = useState(false); 11 | const [addToCartProduct, resInfo] = useAddToCartProductMutation() 12 | useEffect(() => { 13 | if (typeof window !== "undefined") { 14 | const user = localStorage.getItem("user"); 15 | setUser(user) 16 | } 17 | }, [router]); 18 | const productDetails = (id) => { 19 | router.push(`/product/${id}`); 20 | }; 21 | const buyNowProduct = async (item) => { 22 | if (user) { 23 | // console.log(item); 24 | const data = { 25 | id: item._id, 26 | quantity: 1, 27 | } 28 | await addToCartProduct(data) 29 | toast.success("The product add successfully in you cart..!"); 30 | } else { 31 | router.push('/sign-in') 32 | } 33 | } 34 | 35 | return ( 36 |
37 |
38 |
39 | 47 |
48 |
49 |

50 | 56 |

57 |
58 | {item?.keyFeatures?.map((feature, featureIndex) => ( 59 | 60 | ))} 61 |
62 |
63 | ${item?.price} 64 |
65 |
66 |
67 |
68 | {resInfo.isLoading ? : 71 | } 74 |
75 |
76 | 77 | ); 78 | }; 79 | 80 | export default Card; 81 | -------------------------------------------------------------------------------- /src/components/User/ViewAllUser.jsx: -------------------------------------------------------------------------------- 1 | 2 | import { useGetAllUserQuery } from '@/redux/features/auth/userAuth'; 3 | import React from 'react'; 4 | import { useState } from 'react'; 5 | import RoleChangeModal from './RoleChangeModal'; 6 | import DeleteUser from './DeleteUser'; 7 | import LoadingSpinner from '../Shared/Loading/LoadingSpinner'; 8 | 9 | const ViewAllUserf = () => { 10 | const { data, isLoading, isError, refetch } = useGetAllUserQuery(); 11 | const [userRoleChange, setUserRoleChange] = useState(false) 12 | const [deleteUser, setDeleteUser] = useState(false) 13 | const [user, setUser] = useState() 14 | return ( 15 |
16 | {isLoading ? :
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {data?.data?.map((item) => <> 30 | 31 | 34 | 37 | 40 | 54 | 55 | )} 56 | 57 |
User NameUser EmailRoleAction
32 |

{item?.firstName} {item?.lastName}

33 |
35 |

{item?.email}

36 |
38 |

{item?.role}

39 |
41 | 47 | 53 |
58 |
59 | { 60 | userRoleChange && 61 | } 62 | { 63 | deleteUser && 64 | } 65 |
66 |
} 67 |
68 | ); 69 | }; 70 | 71 | export default ViewAllUserf; -------------------------------------------------------------------------------- /src/components/Shared/Navbar/MainNavbar.js: -------------------------------------------------------------------------------- 1 | 2 | import { useRouter } from "next/router"; 3 | import { useState } from "react"; 4 | import { useEffect } from "react"; 5 | import { toast } from "react-hot-toast"; 6 | import { BsPerson } from 'react-icons/bs'; 7 | import { CiShoppingCart } from 'react-icons/ci'; 8 | function MainNavbar() { 9 | const router = useRouter(); 10 | const [user, setUser] = useState(false); 11 | useEffect(() => { 12 | if (typeof window !== "undefined") { 13 | const user = localStorage.getItem("user"); 14 | const jsonObject = JSON.parse(user); 15 | setUser(jsonObject) 16 | } 17 | }, [router]); 18 | const logOut = () => { 19 | toast.success("Your Account Logout Successfully..!"); 20 | localStorage.removeItem("accessToken"); 21 | localStorage.removeItem("refreshToken"); 22 | localStorage.removeItem("user"); 23 | router.push('/') 24 | } 25 | const addToCartFun = () => { 26 | router.push('/add-to-cart') 27 | } 28 | console.log(user); 29 | return ( 30 |
31 |
32 |
33 |
34 | 37 |
38 |
39 |
40 | 41 |
42 | 43 | {user?.role === 'ADMIN' && } 46 | {user?.role === 'ADMIN' && } 49 | {user?.role === 'ADMIN' && } 52 | 55 |
56 |
57 | 58 |
59 |
60 |
61 |

Account

62 |
63 | {!user ?
64 | 65 |

or

66 | 67 |
:
68 | 69 |

or

70 | 71 |
} 72 |
73 |
74 |
75 |
76 |
77 |
78 | ); 79 | } 80 | 81 | export default MainNavbar; 82 | -------------------------------------------------------------------------------- /src/pages/auth/profile.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { useGetUserProfileQuery, useUpdateProfileMutation } from '@/redux/features/auth/userAuth'; 3 | import { useRouter } from 'next/router'; 4 | 5 | const UserProfile = () => { 6 | const { data, isLoading, isError } = useGetUserProfileQuery(); 7 | const [updateProfile, resInfo] = useUpdateProfileMutation() 8 | const router = useRouter(); 9 | const [isEditing, setIsEditing] = useState(false); 10 | const [userData, setUserData] = useState({}); 11 | 12 | useEffect(() => { 13 | if (data) { 14 | setUserData(data?.user); 15 | } 16 | }, [data]); 17 | 18 | const handleEditClick = () => { 19 | setIsEditing(true); 20 | }; 21 | 22 | const handleSaveClick = async () => { 23 | const res = await updateProfile(userData) 24 | if (res) { 25 | setIsEditing(false); 26 | } 27 | }; 28 | 29 | const handleInputChange = (e) => { 30 | const { name, value } = e.target; 31 | setUserData({ 32 | ...userData, 33 | [name]: value, 34 | }); 35 | }; 36 | 37 | return ( 38 |
39 |
40 |

User Profile

41 |
42 | 43 | {isEditing ? ( 44 | 51 | ) : ( 52 |
{userData?.name || ''}
53 | )} 54 |
55 |
56 | 57 | {isEditing ? ( 58 | 65 | ) : ( 66 |
{userData.email || ''}
67 | )} 68 |
69 |
70 | 71 | {isEditing ? ( 72 | 79 | ) : ( 80 |
{userData.phone || ''}
81 | )} 82 |
83 |
84 | 85 | {isEditing ? ( 86 | 92 | ) : ( 93 |
{userData.address || ''}
94 | )} 95 |
96 |
97 | {isEditing ? ( 98 | 104 | ) : ( 105 | 111 | )} 112 | 118 |
119 |
120 |
121 | ); 122 | }; 123 | 124 | export default UserProfile; 125 | -------------------------------------------------------------------------------- /src/pages/profile/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { useGetUserProfileQuery, useUpdateProfileMutation } from '@/redux/features/auth/userAuth'; 3 | import { useRouter } from 'next/router'; 4 | 5 | const UserProfile = () => { 6 | const { data, isLoading, isError } = useGetUserProfileQuery(); 7 | const [updateProfile, resInfo] = useUpdateProfileMutation() 8 | const router = useRouter(); 9 | const [isEditing, setIsEditing] = useState(false); 10 | const [userData, setUserData] = useState({}); 11 | 12 | useEffect(() => { 13 | if (data) { 14 | setUserData(data?.user); 15 | } 16 | }, [data]); 17 | 18 | const handleEditClick = () => { 19 | setIsEditing(true); 20 | }; 21 | 22 | const handleSaveClick = async () => { 23 | const res = await updateProfile(userData) 24 | if (res) { 25 | setIsEditing(false); 26 | } 27 | }; 28 | 29 | const handleInputChange = (e) => { 30 | const { name, value } = e.target; 31 | setUserData({ 32 | ...userData, 33 | [name]: value, 34 | }); 35 | }; 36 | 37 | return ( 38 |
39 |
40 |

User Profile

41 |
42 | 43 | {isEditing ? ( 44 | 51 | ) : ( 52 |
{userData?.name || ''}
53 | )} 54 |
55 |
56 | 57 | {isEditing ? ( 58 | 65 | ) : ( 66 |
{userData.email || ''}
67 | )} 68 |
69 |
70 | 71 | {isEditing ? ( 72 | 79 | ) : ( 80 |
{userData.phone || ''}
81 | )} 82 |
83 |
84 | 85 | {isEditing ? ( 86 | 92 | ) : ( 93 |
{userData.address || ''}
94 | )} 95 |
96 |
97 | {isEditing ? ( 98 | 104 | ) : ( 105 | 111 | )} 112 | 118 |
119 |
120 |
121 | ); 122 | }; 123 | 124 | export default UserProfile; 125 | -------------------------------------------------------------------------------- /src/pages/add-featehr.js: -------------------------------------------------------------------------------- 1 | import { PostImage } from '@/components/ImageBB/imageUpload'; 2 | import { useAddFeatherMutation } from '@/redux/features/productFeather/productFeather'; 3 | import { useState } from 'react'; 4 | 5 | const FeatherPosting = () => { 6 | const [selectedImage, setSelectedImage] = useState(null); 7 | const [image, setImage] = useState(null); 8 | const [uploadProgress, setUploadProgress] = useState(0); 9 | const [addFeather, resCreateFeather] = useAddFeatherMutation() 10 | 11 | const handleImageUpload = async (e) => { 12 | const file = e.target.files[0]; 13 | const imageUrl = await PostImage(file); 14 | setSelectedImage(file); 15 | setImage(imageUrl); 16 | let progress = 0; 17 | const interval = setInterval(() => { 18 | progress += 10; 19 | setUploadProgress(progress); 20 | if (progress === 100) { 21 | clearInterval(interval); 22 | } 23 | }, 100); 24 | }; 25 | const handleSubmit = async (e) => { 26 | e.preventDefault(); 27 | 28 | const data = { 29 | featherName: e.target.featherName.value, 30 | featherPhoto: image, 31 | dis: e.target.description.value, 32 | }; 33 | e.target.reset(); 34 | setSelectedImage(); 35 | await addFeather(data) 36 | }; 37 | return ( 38 |
39 |
40 |

Add Yo 41 |

42 |
43 |
44 | 45 | 51 |
52 |
53 | 54 |