├── Readme.md
├── blockchain
├── .gitignore
├── README.md
├── contracts
│ └── Ecommerce.sol
├── hardhat.config.js
├── package.json
├── scripts
│ └── deploy.js
├── test
│ └── Ecommerce.test.js
└── yarn.lock
└── frontend
├── .eslintrc.json
├── .gitignore
├── README.md
├── components
├── 404-page
│ └── ErrorPage.jsx
├── admin
│ ├── Admin.jsx
│ ├── AdminDashboard.jsx
│ └── TabComp.jsx
├── categories
│ └── Categories.jsx
├── navbar
│ └── Navbar.jsx
├── product-details
│ └── ProductDetail.jsx
└── wallet
│ └── WalletConnect.jsx
├── configs
└── tsConfig.json
├── constants
├── Ecommerce.json
├── index.js
└── urls.js
├── context
└── MainContext.js
├── data
├── carouselData.js
├── dropdownData.js
├── index.js
└── navData.js
├── layouts
└── MainLayout.jsx
├── next.config.js
├── package.json
├── pages
├── 404.jsx
├── [productid].js
├── _app.js
├── admin.js
├── api
│ └── hello.js
├── index.js
└── my-orders.js
├── postcss.config.js
├── public
├── favicon.ico
├── images
│ ├── 404-image.webp
│ ├── categories
│ │ ├── all_img.webp
│ │ ├── camera_img.webp
│ │ ├── clothes_img.webp
│ │ ├── laptops_img.webp
│ │ ├── mobile_img.webp
│ │ ├── television_img.webp
│ │ └── toys_img.webp
│ ├── connect-wallet.png
│ ├── ipad_image.webp
│ ├── login-img.webp
│ └── logo.jpg
└── vercel.svg
├── styles
└── globals.css
├── subcomponents
├── card
│ └── Card1.jsx
├── logo
│ └── Logo.jsx
├── modal
│ └── Modal.jsx
└── particles-ts
│ └── TsParticles.jsx
├── tailwind.config.js
├── utils
└── DateConverter.js
└── yarn.lock
/Readme.md:
--------------------------------------------------------------------------------
1 | # FullStack Ecommerce DApp (Decentralized Application)
2 | Complete Full Stack Decentralization Ecommerce Website using **Solidity** language for Smart Contract, **hardhat** for Dev Enviroment, and Next.js framework For Frontend.
3 |
4 |
5 | ### See Deployed Version -> https://ecommerce-dapp-ten.vercel.app/
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Functionalities :-
20 | - **For Users**
21 | - **See All Products**
22 | - **Filter Products**
23 | - **See perticular productn**
24 | - **Buy The Product**
25 | - **See the past history of products**
26 |
27 |
28 |
29 |
30 | - **For Admin**
31 | - **Add the Product**
32 | - **Upload image, Metadata to IPFS**
33 | - **See the Contract balance.**
34 | - **Withdraw Balance of contract.**
35 |
36 |
37 | ## How to Setup in your local enviroment :-
38 |
39 | ### Frontend
40 | 1. cd frontend
41 | 2. yarn
42 | 3. Setup Env
43 | 3. yarn run dev
44 |
45 |
46 | ### Blockchain
47 | 1. cd blockchain
48 | 2. yarn install
49 | 3. setup env for polygon test network or you can use localhost.
50 | 4. yarn hardhat run scripts/deploy.js --network polygon
51 |
52 |
53 |
54 | ## Technologies/Frameworks Used :-
55 |
56 | ### Frontend
57 | 1. Next.js (Using Vite).
58 | 2. Tailwind CSS and Material-Tailwind (For styling).
59 | 3. **ethers.js** for Web3 integration.
60 | 4. IPFS for storing images.
61 | 5. Alchemy mumbai Testnet (Polygon)
62 |
63 | ## Blockchain
64 | 1. **Solidity** (To develop Smart Contract)
65 | 2. Javascript (For deploying scripts)
66 | 3. **Chai** (For testing Smart Contract)
67 | 4. Polygon (Test network)
68 | 5. Hardhat
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/blockchain/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
3 | coverage
4 | coverage.json
5 | typechain
6 | typechain-types
7 |
8 | #Hardhat files
9 | cache
10 | artifacts
11 |
12 |
--------------------------------------------------------------------------------
/blockchain/README.md:
--------------------------------------------------------------------------------
1 | # Sample Hardhat Project
2 |
3 | This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract.
4 |
5 | Try running some of the following tasks:
6 |
7 | ```shell
8 | npx hardhat help
9 | npx hardhat test
10 | GAS_REPORT=true npx hardhat test
11 | npx hardhat node
12 | npx hardhat run scripts/deploy.js
13 | ```
14 |
--------------------------------------------------------------------------------
/blockchain/contracts/Ecommerce.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.10;
3 |
4 | error Ecommerce__YouAreNoteOwner();
5 | error Ecommerce__PriceNotMet(uint256 _price);
6 |
7 | contract Ecommerce {
8 | /* State Variables */
9 | uint256 private productId;
10 | address private owner;
11 |
12 | constructor() {
13 | owner = msg.sender;
14 | }
15 |
16 | /* structs */
17 | struct ProductStruct {
18 | uint256 price;
19 | uint32 quantity;
20 | string metadata;
21 | }
22 | /* Events */
23 |
24 | // After Adding the product
25 | event productAdded(
26 | string indexed _category,
27 | uint256 indexed _timestamp,
28 | uint256 indexed _productId,
29 | uint256 _price,
30 | string _metadata
31 | );
32 |
33 | // After buying the product
34 | event productBought(
35 | address indexed buyer,
36 | uint256 indexed timestamp,
37 | uint256 _productId,
38 | uint256 price,
39 | string metadata
40 | );
41 |
42 | /* Modifiers */
43 | modifier onlyOwner() {
44 | if (msg.sender != owner) {
45 | revert Ecommerce__YouAreNoteOwner();
46 | }
47 | _;
48 | }
49 |
50 | /* Mappings */
51 | mapping(uint256 => ProductStruct) s_AllProducts;
52 |
53 | /* Logics */
54 |
55 | function addProduct(
56 | uint256 _price,
57 | uint32 _quantity,
58 | string memory _metadata,
59 | string memory _category
60 | ) external onlyOwner {
61 | productId++;
62 | s_AllProducts[productId] = ProductStruct(_price, _quantity, _metadata);
63 | emit productAdded(
64 | _category,
65 | block.timestamp,
66 | productId,
67 | _price,
68 | _metadata
69 | );
70 | }
71 |
72 | function getProduct(uint256 _productId)
73 | external
74 | view
75 | returns (ProductStruct memory)
76 | {
77 | return s_AllProducts[_productId];
78 | }
79 |
80 | // Get the total contract balance
81 | function getContractBalance() external view returns (uint256) {
82 | return address(this).balance;
83 | }
84 |
85 | function updateQuantity(uint32 _quantity, uint256 _productId) external {
86 | s_AllProducts[_productId].quantity = _quantity;
87 | }
88 |
89 | function buyProduct(uint256 _productId) external payable {
90 | if (msg.value != s_AllProducts[_productId].price) {
91 | revert Ecommerce__PriceNotMet(msg.value);
92 | }
93 | string memory metadata = s_AllProducts[_productId].metadata;
94 |
95 | emit productBought(
96 | msg.sender,
97 | block.timestamp,
98 | _productId,
99 | msg.value,
100 | metadata
101 | );
102 | }
103 |
104 | // Withdraw the contract balance.
105 | function withdraw(address _to) external payable onlyOwner {
106 | payable(_to).transfer(address(this).balance);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/blockchain/hardhat.config.js:
--------------------------------------------------------------------------------
1 | require("@nomiclabs/hardhat-waffle");
2 | require('dotenv').config();
3 |
4 | task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
5 | const accounts = await hre.ethers.getSigners();
6 |
7 | for (const account of accounts) {
8 | console.log(account.address);
9 | }
10 | })
11 |
12 | const PRIVATE_KEY = process.env.POLYGON_PRIVATE_KEY
13 | const RPC_URL = process.env.POLYGON_RPC_URL
14 |
15 | module.exports = {
16 | solidity: "0.8.10",
17 | defaultNetwork: "polygon",
18 | networks: {
19 | hardhat: {},
20 | polygon: {
21 | url: RPC_URL,
22 | accounts: [PRIVATE_KEY]
23 | }
24 | }
25 | };
--------------------------------------------------------------------------------
/blockchain/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blockchain",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "@nomicfoundation/hardhat-toolbox": "^1.0.2",
14 | "hardhat": "^2.11.0"
15 | },
16 | "dependencies": {
17 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.0",
18 | "@nomicfoundation/hardhat-network-helpers": "^1.0.0",
19 | "@nomiclabs/hardhat-ethers": "^2.0.0",
20 | "@nomiclabs/hardhat-etherscan": "^3.0.0",
21 | "@nomiclabs/hardhat-waffle": "^2.0.3",
22 | "@typechain/ethers-v5": "^10.1.0",
23 | "@typechain/hardhat": "^6.1.2",
24 | "@types/mocha": "^9.1.0",
25 | "chai": "^4.2.0",
26 | "dotenv": "^16.0.1",
27 | "ethers": "^5.4.7",
28 | "hardhat-gas-reporter": "^1.0.8",
29 | "solidity-coverage": "^0.7.21",
30 | "ts-node": ">=8.0.0",
31 | "typechain": "^8.1.0",
32 | "typescript": ">=4.5.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/blockchain/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | const hre = require('hardhat');
2 |
3 | async function main() {
4 |
5 | const Ecommerce = await hre.ethers.getContractFactory("Ecommerce")
6 | const ecommerce = await Ecommerce.deploy();
7 |
8 | await ecommerce.deployed();
9 |
10 | console.log("contract deployed to:", ecommerce.address);
11 | }
12 |
13 | main()
14 | .then(() => process.exit(0))
15 | .catch((error) => {
16 | console.log(error);
17 | process.exit(1);
18 | });
--------------------------------------------------------------------------------
/blockchain/test/Ecommerce.test.js:
--------------------------------------------------------------------------------
1 | const {
2 | time,
3 | loadFixture,
4 | } = require("@nomicfoundation/hardhat-network-helpers");
5 | const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
6 | const { expect } = require("chai");
7 |
8 | describe("Ecommerce", function () {
9 | // We define a fixture to reuse the same setup in every test.
10 | // We use loadFixture to run this setup once, snapshot that state,
11 | // and reset Hardhat Network to that snapshot in every test.
12 | async function deployOneYearLockFixture() {
13 | // Contracts are deployed using the first signer/account by default
14 | const [owner, otherAccount] = await ethers.getSigners();
15 |
16 | const Ecommerce = await ethers.getContractFactory("Ecommerce");
17 | const ecommerce = await Ecommerce.deploy();
18 |
19 | return { ecommerce, owner, otherAccount };
20 | }
21 |
22 | describe("Deployment", function () {
23 | it("Should set the right owner", async function () {
24 | const { ecommerce, owner } = await loadFixture(deployOneYearLockFixture);
25 | expect(ecommerce.addProduct()).not.to.be.reverted;
26 |
27 | expect(await ecommerce.addProduct()).to.not.equals(owner.address);
28 | });
29 |
30 | it("Should receive and store the funds to lock", async function () {
31 | const { lock, lockedAmount } = await loadFixture(
32 | deployOneYearLockFixture
33 | );
34 |
35 | expect(await ethers.provider.getBalance(lock.address)).to.equal(
36 | lockedAmount
37 | );
38 | });
39 |
40 | it("Should fail if the unlockTime is not in the future", async function () {
41 | // We don't use the fixture here because we want a different deployment
42 | const latestTime = await time.latest();
43 | const Lock = await ethers.getContractFactory("Lock");
44 | await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
45 | "Unlock time should be in the future"
46 | );
47 | });
48 | });
49 |
50 | describe("Withdrawals", function () {
51 | describe("Validations", function () {
52 | it("Should revert with the right error if called too soon", async function () {
53 | const { lock } = await loadFixture(deployOneYearLockFixture);
54 |
55 | await expect(lock.withdraw()).to.be.revertedWith(
56 | "You can't withdraw yet"
57 | );
58 | });
59 |
60 | it("Should revert with the right error if called from another account", async function () {
61 | const { lock, unlockTime, otherAccount } = await loadFixture(
62 | deployOneYearLockFixture
63 | );
64 |
65 | // We can increase the time in Hardhat Network
66 | await time.increaseTo(unlockTime);
67 |
68 | await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith(
69 | "You aren't the owner"
70 | );
71 | });
72 |
73 | it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () {
74 | const { lock, unlockTime } = await loadFixture(
75 | deployOneYearLockFixture
76 | );
77 |
78 | await time.increaseTo(unlockTime);
79 |
80 | await expect(lock.withdraw()).not.to.be.reverted;
81 | });
82 | });
83 |
84 | describe("Events", function () {
85 | it("Should emit an event on withdrawals", async function () {
86 | const { lock, unlockTime, lockedAmount } = await loadFixture(
87 | deployOneYearLockFixture
88 | );
89 |
90 | await time.increaseTo(unlockTime);
91 |
92 | await expect(lock.withdraw())
93 | .to.emit(lock, "Withdrawal")
94 | .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg
95 | });
96 | });
97 |
98 | describe("Transfers", function () {
99 | it("Should transfer the funds to the owner", async function () {
100 | const { lock, unlockTime, lockedAmount, owner } = await loadFixture(
101 | deployOneYearLockFixture
102 | );
103 |
104 | await time.increaseTo(unlockTime);
105 |
106 | await expect(lock.withdraw()).to.changeEtherBalances(
107 | [owner, lock],
108 | [lockedAmount, -lockedAmount]
109 | );
110 | });
111 | });
112 | });
113 | });
114 |
--------------------------------------------------------------------------------
/frontend/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | .env
9 |
10 | # testing
11 | /coverage
12 |
13 | # next.js
14 | /.next/
15 | /out/
16 |
17 | # production
18 | /build
19 |
20 | # misc
21 | .DS_Store
22 | *.pem
23 |
24 | # debug
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log*
28 | .pnpm-debug.log*
29 |
30 | # local env files
31 | .env*.local
32 |
33 | # vercel
34 | .vercel
35 |
36 | # typescript
37 | *.tsbuildinfo
38 | next-env.d.ts
39 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/frontend/components/404-page/ErrorPage.jsx:
--------------------------------------------------------------------------------
1 | import Link from 'next/link'
2 | import React from 'react'
3 | import Logo from '../../subcomponents/logo/Logo'
4 |
5 | export default function ErrorPage({title, description, image, alt}) {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {title}
17 |
18 |
{description}
19 |
Use the Go Back button below.
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |

32 |
33 |
34 |
35 |
36 |
37 |
38 | )
39 | }
40 |
--------------------------------------------------------------------------------
/frontend/components/admin/Admin.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import {
3 | CONTRACT_ADDRESS,
4 | IPFS_URL,
5 | PROJECT_ID,
6 | PROJECT_SECRET,
7 | } from "../../constants";
8 | import EcomABI from "../../constants/Ecommerce.json";
9 | import { categories } from "../../data";
10 | import { create as ipfsHttpClient } from "ipfs-http-client";
11 | import { useRouter } from "next/router";
12 | import { MdAddTask } from "react-icons/md";
13 | import {
14 | Input,
15 | Textarea,
16 | Select,
17 | Option,
18 | Button,
19 | IconButton,
20 | Typography,
21 | } from "@material-tailwind/react";
22 | // import TsParticles from "../../subcomponents/particles-ts/TsParticles";
23 | import { ToastContainer, toast } from "react-toastify";
24 | import "react-toastify/dist/ReactToastify.css";
25 | import { ethers } from "ethers";
26 | import { MainContext } from "../../context/MainContext";
27 |
28 | export default function Admin() {
29 | const {requestContract} = useContext(MainContext);
30 | /* IPFS Authentication ------------------------------------------------------------------ */
31 |
32 | const auth =
33 | "Basic " +
34 | Buffer.from(PROJECT_ID + ":" + PROJECT_SECRET).toString("base64");
35 |
36 | // IPFS Client --
37 | const client = ipfsHttpClient({
38 | host: "ipfs.infura.io",
39 | port: 5001,
40 | protocol: "https",
41 | headers: {
42 | authorization: auth,
43 | },
44 | });
45 |
46 | /* Use States ------------------------------------------------------------------ */
47 | const [isLoading, setIsLoading] = useState(false);
48 | const [formData, setFormData] = useState({
49 | title: "",
50 | description: "",
51 | price: "",
52 | qunatity: "",
53 | });
54 | const [category, setCategory] = useState("");
55 | const [file, setFile] = useState("");
56 |
57 | // on change of any input.
58 | const handleInputChange = (e) => {
59 | setFormData({ ...formData, [e.target.name]: e.target.value });
60 | };
61 |
62 | // When image is changed.
63 | const onChangeFiles = async (e) => {
64 | const fileData = e.target.files[0];
65 | try {
66 | const add = await client.add(fileData, {
67 | progress: (prog) => console.log("Image is uploaded : ", prog),
68 | });
69 | const url = `${add.path}`;
70 | toast.success("Product Image Uploaded!");
71 | setFile(url);
72 | } catch (error) {
73 | console.log("Error...", error);
74 | toast.error("Error While uploading Image, Try Again");
75 | }
76 | };
77 |
78 | const handleClick = async () => {
79 | const { title, description, price, qunatity } = formData;
80 | if (!title || !description || !file || !price || !qunatity || !category) {
81 | toast.error("Some Feilds Are Missing");
82 | return;
83 | }
84 |
85 | try {
86 | setIsLoading(true);
87 | const metadata = {
88 | title,
89 | description,
90 | imageURL: file,
91 | };
92 | const stringifyData = JSON.stringify(metadata)
93 |
94 | const add = await client.add(stringifyData);
95 | const url = `${add.path}`;
96 | toast.success("Product Data Uploaded!");
97 |
98 | const amountInWEI = ethers.utils.parseEther(price);
99 |
100 | const contract = await requestContract()
101 |
102 | const productData = await contract.addProduct(
103 | amountInWEI,
104 | qunatity,
105 | url,
106 | category
107 | );
108 | toast.promise(productData.wait(), {
109 | pending: "Wait...",
110 | success: "Product Successfully Added👌",
111 | error: "Some Error Occured. 🤯",
112 | });
113 | await productData.wait();
114 |
115 | if (productData.to) {
116 | setFormData({ title: "", description: "", price: "", qunatity: "" });
117 | setFile("");
118 | setCategory("");
119 | setIsLoading(false);
120 |
121 | }
122 | } catch (error) {
123 | console.log("error... ", error);
124 | toast.error("Error occured. Please try Again.");
125 | setIsLoading(false);
126 | }
127 | };
128 |
129 | return (
130 |
131 |
Add Product
132 | {/*
*/}
133 |
134 |
135 |
210 |
211 | );
212 | }
213 |
--------------------------------------------------------------------------------
/frontend/components/admin/AdminDashboard.jsx:
--------------------------------------------------------------------------------
1 | import { Button, Input, Typography } from "@material-tailwind/react";
2 | import { ethers } from "ethers";
3 | import React, { useContext, useEffect, useState } from "react";
4 | import { AiOutlineArrowRight } from "react-icons/ai";
5 | import { FaEthereum } from "react-icons/fa";
6 | import { MainContext } from "../../context/MainContext";
7 | import { ToastContainer, toast } from "react-toastify";
8 | import "react-toastify/dist/ReactToastify.css";
9 |
10 | export default function AdminDashboard() {
11 | const [isAdminWithdrawing, setIsAdminWithdrawing] = useState(false);
12 | const [withdrawAddress, setWithdrawAddress] = useState("");
13 | const [contractBalance, setContractBalance] = useState("Wait..");
14 | const { requestContract } = useContext(MainContext);
15 |
16 | const getContractBalance = async () => {
17 | const contract = await requestContract();
18 | const getBalance = await contract.getContractBalance();
19 | const formatEther = ethers.utils.formatEther(getBalance);
20 | // console.log(formatEther);
21 | setContractBalance(formatEther);
22 | return formatEther;
23 | };
24 | useEffect(() => {
25 | getContractBalance();
26 | }, []);
27 |
28 | const withdrawMoney = async () => {
29 | if (!withdrawAddress) return;
30 | try {
31 | toast.info("Wait..");
32 | const contract = await requestContract();
33 | const tx = await contract.withdraw(withdrawAddress);
34 | toast.promise(tx.wait(), {
35 | pending: "Wait...",
36 | success: "Money Withdraw Success to Address -> " + withdrawAddress,
37 | error: "Some Error Occured. 🤯",
38 | });
39 | await tx.wait();
40 | } catch (error) {
41 | console.log(error);
42 | toast.error("Some Error Occured. 🤯");
43 | }
44 | };
45 | return (
46 |
47 |
48 |
Admin Dashobard
49 |
50 |
54 | Contract Balance :
55 |
56 |
57 | {contractBalance && contractBalance} Ether
58 |
59 |
60 | {isAdminWithdrawing && (
61 | <>
62 |
63 | {
68 | setWithdrawAddress(e.target.value);
69 | }}
70 | label="Enter Account Address"
71 | />
72 |
73 |
82 | >
83 | )}
84 | {isAdminWithdrawing ? (
85 |
94 | ) : (
95 |
103 | )}
104 |
105 |
106 | );
107 | }
108 |
--------------------------------------------------------------------------------
/frontend/components/admin/TabComp.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | Tabs,
3 | TabsHeader,
4 | TabsBody,
5 | Tab,
6 | TabPanel,
7 | } from "@material-tailwind/react";
8 |
9 | export default function TabComp({ data }) {
10 | return (
11 |
12 |
13 | {data.map(({ label, value }) => (
14 |
15 | {label}
16 |
17 | ))}
18 |
19 |
26 | {data.map(({ value, desc }) => (
27 |
28 | {desc}
29 |
30 | ))}
31 |
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/frontend/components/categories/Categories.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { homePageCategories } from "../../data";
3 |
4 | export default function Categories({setSelectedCategory}) {
5 | return (
6 |
7 | {homePageCategories?.map((category, index) => (
8 |
setSelectedCategory(category.url)} className="cateBox" key={index}>
9 |

10 |
{category.text}
11 |
12 | ))}
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/components/navbar/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import Link from "next/link";
3 | import { navLinks } from "../../data";
4 | import { AiOutlineMenuUnfold, AiOutlineMenuFold } from "react-icons/ai";
5 | import { useRouter } from "next/router";
6 | import WalletConnect from "../wallet/WalletConnect";
7 | import Logo from "../../subcomponents/logo/Logo";
8 | import { Button } from "@material-tailwind/react";
9 | import { urls } from "../../constants";
10 | import { MainContext } from "../../context/MainContext";
11 |
12 | export default function Navbar() {
13 | const router = useRouter();
14 | const {isAdmin} = useContext(MainContext)
15 | const [isMobileNavOpen, setisMobileNavOpen] = useState(false); // For toggling the mobile nav
16 | return (
17 |
18 |
19 |
20 |
21 |
22 | {/* Logo */}
23 |
24 |
25 |
26 |
27 |
28 |
48 |
49 | {/* After all nav links if you want any button in right then it will come here */}
50 |
51 | {isAdmin() && }
52 |
53 |
54 |
55 | {/* Hamberger Menu */}
56 |
57 | {isMobileNavOpen ? (
58 |
setisMobileNavOpen(false)}
60 | className="rounded text-2xl"
61 | />
62 | ) : (
63 | setisMobileNavOpen(true)}
65 | className="rounded text-2xl"
66 | />
67 | )}
68 |
69 |
70 |
71 |
72 | {/* Mobile Navbar */}
73 |
79 |
80 |
81 | {/* Logo */}
82 |
83 |
84 | {/* Links */}
85 | {navLinks?.map(({ title, link, icon }, id) => (
86 |
87 |
95 |
96 | {icon}
97 |
98 | {title}
99 |
100 |
101 | ))}
102 | {isAdmin() &&
}
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | );
111 | }
112 |
--------------------------------------------------------------------------------
/frontend/components/product-details/ProductDetail.jsx:
--------------------------------------------------------------------------------
1 | import { Button, Input, Typography } from "@material-tailwind/react";
2 | import React, { useContext, useEffect, useState } from "react";
3 | import { AiOutlineArrowRight } from "react-icons/ai";
4 | import { FaEthereum } from "react-icons/fa";
5 | import { IPFS_URL } from "../../constants";
6 | import { MainContext } from "../../context/MainContext";
7 | import Modal from "../../subcomponents/modal/Modal";
8 |
9 | export default function ProductDetail({
10 | updateProduct,
11 | productId,
12 | metadata,
13 | price,
14 | quantity,
15 | quantityInput,
16 | setQuantityInput,
17 | open,
18 | setOpen,
19 | children,
20 | }) {
21 | const { isAdmin } = useContext(MainContext);
22 | const [parsedMetaData, setParsedMetaData] = useState({});
23 | useEffect(() => {
24 | const fetchMetaData = async () => {
25 | const data = await fetch(`${IPFS_URL}${metadata}`);
26 | const JSONData = await data.json();
27 | setParsedMetaData(JSONData);
28 | };
29 | fetchMetaData();
30 | }, []);
31 | return (
32 | <>
33 | {!parsedMetaData ? (
34 | "loading..."
35 | ) : (
36 |
37 |
38 |
39 |

44 |
45 |
46 |
47 |
48 | {parsedMetaData?.title}
49 |
50 |
{parsedMetaData?.description}
51 |
52 | Total Quantity Available : {quantity} Units
53 | {isAdmin() && (
54 |
55 |
60 |
61 |
66 | Current Quantity : {quantity}
67 |
68 |
69 |
{
74 | setQuantityInput(e.target.value);
75 | }}
76 | label="Enter New Quantity"
77 | />
78 |
87 |
88 |
89 |
90 | )}
91 |
92 |
93 | Price :
94 |
95 | {price} Ether
96 |
97 |
98 |
{children}
99 |
100 |
101 |
102 | )}
103 | >
104 | );
105 | }
106 |
--------------------------------------------------------------------------------
/frontend/components/wallet/WalletConnect.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext } from "react";
2 | import { ethers } from "ethers";
3 | import { AiOutlinePlus } from "react-icons/ai";
4 | import { Button } from "@material-tailwind/react";
5 | import { MainContext } from "../../context/MainContext";
6 | import { ToastContainer, toast } from "react-toastify";
7 | import "react-toastify/dist/ReactToastify.css";
8 |
9 |
10 | const networks = {
11 | polygon: {
12 | chainId: `0x${Number(80001).toString(16)}`,
13 | chainName: "Polygon Testnet",
14 | nativeCurrency: {
15 | name: "MATIC",
16 | symbol: "MATIC",
17 | decimals: 18,
18 | },
19 | rpcUrls: ["https://rpc-mumbai.maticvigil.com/"],
20 | blockExplorerUrls: ["https://mumbai.polygonscan.com/"],
21 | },
22 | };
23 |
24 | export default function WalletConnect() {
25 | const {accountAddress, setAccountAddress} = useContext(MainContext)
26 | const [balance, setBalance] = useState("");
27 | const [loading, setLoading] = useState(false);
28 |
29 | useEffect(() => {
30 | if (window) {
31 | if (window.ethereum) {
32 | window.ethereum.on("accountsChanged", (accounts) => {
33 | if (accounts.length > 0) {
34 | setAccountAddress(accounts[0]);
35 | connectWallet();
36 | } else {
37 | setAccountAddress("");
38 | setBalance("");
39 | localStorage.removeItem("injected");
40 | console.log("Disconnected");
41 | }
42 | });
43 | }
44 | }
45 |
46 | if (localStorage.getItem("injected")) {
47 | connectWallet();
48 | }
49 | }, []);
50 |
51 | const connectWallet = async () => {
52 | try {
53 | setLoading(true);
54 | await window.ethereum.request({ method: "eth_requestAccounts" });
55 | const provider = new ethers.providers.Web3Provider(
56 | window.ethereum,
57 | "any"
58 | );
59 | if (provider.network !== "matic") {
60 | await window.ethereum.request({
61 | method: "wallet_addEthereumChain",
62 | params: [
63 | {
64 | ...networks["polygon"],
65 | },
66 | ],
67 | });
68 | }
69 | const account = provider.getSigner();
70 | const Address = await account.getAddress();
71 | setAccountAddress(Address);
72 | const Balance = ethers.utils.formatEther(await account.getBalance());
73 | setBalance(Balance);
74 | localStorage.setItem("injected", "web3");
75 |
76 | setLoading(false);
77 | } catch (error) {
78 | setLoading(false);
79 | toast.error("Error Encountered! Please try to Connect Wallet Again.")
80 | console.log("Error while connected wallet ", error);
81 | }
82 | };
83 |
84 | return (
85 |
86 | {accountAddress.length > 2 ? (
87 |
88 |
89 |
90 | {accountAddress.slice(0, 6)}...{accountAddress.slice(accountAddress.length - 4)}
91 |
92 |
93 | {balance.slice(0, 4)} ETH
94 |
95 |
96 | ) : (
97 |
101 | )}
102 |
103 | );
104 | }
105 |
--------------------------------------------------------------------------------
/frontend/configs/tsConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "fullScreen": {
3 | "enable": true,
4 | "zIndex": 1
5 | },
6 | "particles": {
7 | "number": {
8 | "value": 50,
9 | "density": {
10 | "enable": false,
11 | "value_area": 800
12 | }
13 | },
14 | "color": {
15 | "value": "#fff"
16 | },
17 | "shape": {
18 | "type": "star",
19 | "options": {
20 | "sides": 5
21 | }
22 | },
23 | "opacity": {
24 | "value": 0.5,
25 | "random": false,
26 | "anim": {
27 | "enable": false,
28 | "speed": 1,
29 | "opacity_min": 0.1,
30 | "sync": false
31 | }
32 | },
33 | "size": {
34 | "value": 4,
35 | "random": true,
36 | "anim": {
37 | "enable": false,
38 | "speed": 70,
39 | "size_min": 0.1,
40 | "sync": false
41 | }
42 | },
43 | "rotate": {
44 | "value": 0,
45 | "random": true,
46 | "direction": "clockwise",
47 | "animation": {
48 | "enable": true,
49 | "speed": 5,
50 | "sync": false
51 | }
52 | },
53 | "line_linked": {
54 | "enable": false,
55 | "distance": 600,
56 | "color": "#ffffff",
57 | "opacity": 0.4,
58 | "width": 2
59 | },
60 | "move": {
61 | "enable": true,
62 | "speed": 2,
63 | "direction": "none",
64 | "random": false,
65 | "straight": false,
66 | "out_mode": "out",
67 | "attract": {
68 | "enable": false,
69 | "rotateX": 600,
70 | "rotateY": 1200
71 | }
72 | }
73 | },
74 | "interactivity": {
75 | "events": {
76 | "onhover": {
77 | "enable": false,
78 | "mode": ["grab"]
79 | },
80 | "onclick": {
81 | "enable": false,
82 | "mode": "bubble"
83 | },
84 | "resize": true
85 | },
86 | "modes": {
87 | "grab": {
88 | "distance": 400,
89 | "line_linked": {
90 | "opacity": 1
91 | }
92 | },
93 | "bubble": {
94 | "distance": 400,
95 | "size": 40,
96 | "duration": 2,
97 | "opacity": 8,
98 | "speed": 3
99 | },
100 | "repulse": {
101 | "distance": 200
102 | },
103 | "push": {
104 | "particles_nb": 4
105 | },
106 | "remove": {
107 | "particles_nb": 2
108 | }
109 | }
110 | },
111 | "retina_detect": true,
112 | "background": {
113 | "color": "green",
114 | "image": "",
115 | "position": "50% 50%",
116 | "repeat": "no-repeat",
117 | "size": "cover"
118 | }
119 | }
--------------------------------------------------------------------------------
/frontend/constants/Ecommerce.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Ecommerce",
4 | "sourceName": "contracts/Ecommerce.sol",
5 | "abi": [
6 | {
7 | "inputs": [],
8 | "stateMutability": "nonpayable",
9 | "type": "constructor"
10 | },
11 | {
12 | "inputs": [
13 | {
14 | "internalType": "uint256",
15 | "name": "_price",
16 | "type": "uint256"
17 | }
18 | ],
19 | "name": "Ecommerce__PriceNotMet",
20 | "type": "error"
21 | },
22 | {
23 | "inputs": [],
24 | "name": "Ecommerce__YouAreNoteOwner",
25 | "type": "error"
26 | },
27 | {
28 | "anonymous": false,
29 | "inputs": [
30 | {
31 | "indexed": true,
32 | "internalType": "string",
33 | "name": "_category",
34 | "type": "string"
35 | },
36 | {
37 | "indexed": true,
38 | "internalType": "uint256",
39 | "name": "_timestamp",
40 | "type": "uint256"
41 | },
42 | {
43 | "indexed": true,
44 | "internalType": "uint256",
45 | "name": "_productId",
46 | "type": "uint256"
47 | },
48 | {
49 | "indexed": false,
50 | "internalType": "uint256",
51 | "name": "_price",
52 | "type": "uint256"
53 | },
54 | {
55 | "indexed": false,
56 | "internalType": "string",
57 | "name": "_metadata",
58 | "type": "string"
59 | }
60 | ],
61 | "name": "productAdded",
62 | "type": "event"
63 | },
64 | {
65 | "anonymous": false,
66 | "inputs": [
67 | {
68 | "indexed": true,
69 | "internalType": "address",
70 | "name": "buyer",
71 | "type": "address"
72 | },
73 | {
74 | "indexed": true,
75 | "internalType": "uint256",
76 | "name": "timestamp",
77 | "type": "uint256"
78 | },
79 | {
80 | "indexed": false,
81 | "internalType": "uint256",
82 | "name": "_productId",
83 | "type": "uint256"
84 | },
85 | {
86 | "indexed": false,
87 | "internalType": "uint256",
88 | "name": "price",
89 | "type": "uint256"
90 | },
91 | {
92 | "indexed": false,
93 | "internalType": "string",
94 | "name": "metadata",
95 | "type": "string"
96 | }
97 | ],
98 | "name": "productBought",
99 | "type": "event"
100 | },
101 | {
102 | "inputs": [
103 | {
104 | "internalType": "uint256",
105 | "name": "_price",
106 | "type": "uint256"
107 | },
108 | {
109 | "internalType": "uint32",
110 | "name": "_quantity",
111 | "type": "uint32"
112 | },
113 | {
114 | "internalType": "string",
115 | "name": "_metadata",
116 | "type": "string"
117 | },
118 | {
119 | "internalType": "string",
120 | "name": "_category",
121 | "type": "string"
122 | }
123 | ],
124 | "name": "addProduct",
125 | "outputs": [],
126 | "stateMutability": "nonpayable",
127 | "type": "function"
128 | },
129 | {
130 | "inputs": [
131 | {
132 | "internalType": "uint256",
133 | "name": "_productId",
134 | "type": "uint256"
135 | }
136 | ],
137 | "name": "buyProduct",
138 | "outputs": [],
139 | "stateMutability": "payable",
140 | "type": "function"
141 | },
142 | {
143 | "inputs": [],
144 | "name": "getContractBalance",
145 | "outputs": [
146 | {
147 | "internalType": "uint256",
148 | "name": "",
149 | "type": "uint256"
150 | }
151 | ],
152 | "stateMutability": "view",
153 | "type": "function"
154 | },
155 | {
156 | "inputs": [
157 | {
158 | "internalType": "uint256",
159 | "name": "_productId",
160 | "type": "uint256"
161 | }
162 | ],
163 | "name": "getProduct",
164 | "outputs": [
165 | {
166 | "components": [
167 | {
168 | "internalType": "uint256",
169 | "name": "price",
170 | "type": "uint256"
171 | },
172 | {
173 | "internalType": "uint32",
174 | "name": "quantity",
175 | "type": "uint32"
176 | },
177 | {
178 | "internalType": "string",
179 | "name": "metadata",
180 | "type": "string"
181 | }
182 | ],
183 | "internalType": "struct Ecommerce.ProductStruct",
184 | "name": "",
185 | "type": "tuple"
186 | }
187 | ],
188 | "stateMutability": "view",
189 | "type": "function"
190 | },
191 | {
192 | "inputs": [
193 | {
194 | "internalType": "uint32",
195 | "name": "_quantity",
196 | "type": "uint32"
197 | },
198 | {
199 | "internalType": "uint256",
200 | "name": "_productId",
201 | "type": "uint256"
202 | }
203 | ],
204 | "name": "updateQuantity",
205 | "outputs": [],
206 | "stateMutability": "nonpayable",
207 | "type": "function"
208 | },
209 | {
210 | "inputs": [
211 | {
212 | "internalType": "address",
213 | "name": "_to",
214 | "type": "address"
215 | }
216 | ],
217 | "name": "withdraw",
218 | "outputs": [],
219 | "stateMutability": "payable",
220 | "type": "function"
221 | }
222 | ],
223 | "bytecode": "0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610da7806100616000396000f3fe6080604052600436106100555760003560e01c806351cff8d91461005a5780636f9fb98a146100765780638642269e146100a1578063923a7218146100bd578063b9db15b4146100e6578063ec79f4eb14610123575b600080fd5b610074600480360381019061006f919061075a565b61014c565b005b34801561008257600080fd5b5061008b61021d565b60405161009891906107a0565b60405180910390f35b6100bb60048036038101906100b691906107e7565b610225565b005b3480156100c957600080fd5b506100e460048036038101906100df9190610850565b610379565b005b3480156100f257600080fd5b5061010d600480360381019061010891906107e7565b6103b2565b60405161011a9190610997565b60405180910390f35b34801561012f57600080fd5b5061014a60048036038101906101459190610aee565b6104a1565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d3576040517fe88d976a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610219573d6000803e3d6000fd5b5050565b600047905090565b6002600082815260200190815260200160002060000154341461027f57346040517faf7e1aab00000000000000000000000000000000000000000000000000000000815260040161027691906107a0565b60405180910390fd5b60006002600083815260200190815260200160002060020180546102a290610bbc565b80601f01602080910402602001604051908101604052809291908181526020018280546102ce90610bbc565b801561031b5780601f106102f05761010080835404028352916020019161031b565b820191906000526020600020905b8154815290600101906020018083116102fe57829003601f168201915b50505050509050423373ffffffffffffffffffffffffffffffffffffffff167f0a11095d165b5fd30537fe537d9f797c4b3a88f5cfdda4179d6e00ee6e91385884348560405161036d93929190610c38565b60405180910390a35050565b816002600083815260200190815260200160002060010160006101000a81548163ffffffff021916908363ffffffff1602179055505050565b6103ba61061e565b60026000838152602001908152602001600020604051806060016040529081600082015481526020016001820160009054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160028201805461041890610bbc565b80601f016020809104026020016040519081016040528092919081815260200182805461044490610bbc565b80156104915780601f1061046657610100808354040283529160200191610491565b820191906000526020600020905b81548152906001019060200180831161047457829003601f168201915b5050505050815250509050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610528576040517fe88d976a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008081548092919061053a90610ca5565b919050555060405180606001604052808581526020018463ffffffff1681526020018381525060026000805481526020019081526020016000206000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160020190805190602001906105c1929190610645565b5090505060005442826040516105d79190610d2a565b60405180910390207f0bb77d0e0ce5caef0bfacd80ad2e68ca13340d38338e094f87bfe190b9c59ebf8786604051610610929190610d41565b60405180910390a450505050565b604051806060016040528060008152602001600063ffffffff168152602001606081525090565b82805461065190610bbc565b90600052602060002090601f01602090048101928261067357600085556106ba565b82601f1061068c57805160ff19168380011785556106ba565b828001600101855582156106ba579182015b828111156106b957825182559160200191906001019061069e565b5b5090506106c791906106cb565b5090565b5b808211156106e45760008160009055506001016106cc565b5090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610727826106fc565b9050919050565b6107378161071c565b811461074257600080fd5b50565b6000813590506107548161072e565b92915050565b6000602082840312156107705761076f6106f2565b5b600061077e84828501610745565b91505092915050565b6000819050919050565b61079a81610787565b82525050565b60006020820190506107b56000830184610791565b92915050565b6107c481610787565b81146107cf57600080fd5b50565b6000813590506107e1816107bb565b92915050565b6000602082840312156107fd576107fc6106f2565b5b600061080b848285016107d2565b91505092915050565b600063ffffffff82169050919050565b61082d81610814565b811461083857600080fd5b50565b60008135905061084a81610824565b92915050565b60008060408385031215610867576108666106f2565b5b60006108758582860161083b565b9250506020610886858286016107d2565b9150509250929050565b61089981610787565b82525050565b6108a881610814565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156108e85780820151818401526020810190506108cd565b838111156108f7576000848401525b50505050565b6000601f19601f8301169050919050565b6000610919826108ae565b61092381856108b9565b93506109338185602086016108ca565b61093c816108fd565b840191505092915050565b600060608301600083015161095f6000860182610890565b506020830151610972602086018261089f565b506040830151848203604086015261098a828261090e565b9150508091505092915050565b600060208201905081810360008301526109b18184610947565b905092915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6109fb826108fd565b810181811067ffffffffffffffff82111715610a1a57610a196109c3565b5b80604052505050565b6000610a2d6106e8565b9050610a3982826109f2565b919050565b600067ffffffffffffffff821115610a5957610a586109c3565b5b610a62826108fd565b9050602081019050919050565b82818337600083830152505050565b6000610a91610a8c84610a3e565b610a23565b905082815260208101848484011115610aad57610aac6109be565b5b610ab8848285610a6f565b509392505050565b600082601f830112610ad557610ad46109b9565b5b8135610ae5848260208601610a7e565b91505092915050565b60008060008060808587031215610b0857610b076106f2565b5b6000610b16878288016107d2565b9450506020610b278782880161083b565b935050604085013567ffffffffffffffff811115610b4857610b476106f7565b5b610b5487828801610ac0565b925050606085013567ffffffffffffffff811115610b7557610b746106f7565b5b610b8187828801610ac0565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610bd457607f821691505b60208210811415610be857610be7610b8d565b5b50919050565b600082825260208201905092915050565b6000610c0a826108ae565b610c148185610bee565b9350610c248185602086016108ca565b610c2d816108fd565b840191505092915050565b6000606082019050610c4d6000830186610791565b610c5a6020830185610791565b8181036040830152610c6c8184610bff565b9050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610cb082610787565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610ce357610ce2610c76565b5b600182019050919050565b600081905092915050565b6000610d04826108ae565b610d0e8185610cee565b9350610d1e8185602086016108ca565b80840191505092915050565b6000610d368284610cf9565b915081905092915050565b6000604082019050610d566000830185610791565b8181036020830152610d688184610bff565b9050939250505056fea264697066735822122098a78c048a00b8794a9509dcb7a66d4ba197be12c71f75ae2264b5a67c34cd4b64736f6c634300080a0033",
224 | "deployedBytecode": "0x6080604052600436106100555760003560e01c806351cff8d91461005a5780636f9fb98a146100765780638642269e146100a1578063923a7218146100bd578063b9db15b4146100e6578063ec79f4eb14610123575b600080fd5b610074600480360381019061006f919061075a565b61014c565b005b34801561008257600080fd5b5061008b61021d565b60405161009891906107a0565b60405180910390f35b6100bb60048036038101906100b691906107e7565b610225565b005b3480156100c957600080fd5b506100e460048036038101906100df9190610850565b610379565b005b3480156100f257600080fd5b5061010d600480360381019061010891906107e7565b6103b2565b60405161011a9190610997565b60405180910390f35b34801561012f57600080fd5b5061014a60048036038101906101459190610aee565b6104a1565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d3576040517fe88d976a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610219573d6000803e3d6000fd5b5050565b600047905090565b6002600082815260200190815260200160002060000154341461027f57346040517faf7e1aab00000000000000000000000000000000000000000000000000000000815260040161027691906107a0565b60405180910390fd5b60006002600083815260200190815260200160002060020180546102a290610bbc565b80601f01602080910402602001604051908101604052809291908181526020018280546102ce90610bbc565b801561031b5780601f106102f05761010080835404028352916020019161031b565b820191906000526020600020905b8154815290600101906020018083116102fe57829003601f168201915b50505050509050423373ffffffffffffffffffffffffffffffffffffffff167f0a11095d165b5fd30537fe537d9f797c4b3a88f5cfdda4179d6e00ee6e91385884348560405161036d93929190610c38565b60405180910390a35050565b816002600083815260200190815260200160002060010160006101000a81548163ffffffff021916908363ffffffff1602179055505050565b6103ba61061e565b60026000838152602001908152602001600020604051806060016040529081600082015481526020016001820160009054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160028201805461041890610bbc565b80601f016020809104026020016040519081016040528092919081815260200182805461044490610bbc565b80156104915780601f1061046657610100808354040283529160200191610491565b820191906000526020600020905b81548152906001019060200180831161047457829003601f168201915b5050505050815250509050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610528576040517fe88d976a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008081548092919061053a90610ca5565b919050555060405180606001604052808581526020018463ffffffff1681526020018381525060026000805481526020019081526020016000206000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160020190805190602001906105c1929190610645565b5090505060005442826040516105d79190610d2a565b60405180910390207f0bb77d0e0ce5caef0bfacd80ad2e68ca13340d38338e094f87bfe190b9c59ebf8786604051610610929190610d41565b60405180910390a450505050565b604051806060016040528060008152602001600063ffffffff168152602001606081525090565b82805461065190610bbc565b90600052602060002090601f01602090048101928261067357600085556106ba565b82601f1061068c57805160ff19168380011785556106ba565b828001600101855582156106ba579182015b828111156106b957825182559160200191906001019061069e565b5b5090506106c791906106cb565b5090565b5b808211156106e45760008160009055506001016106cc565b5090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610727826106fc565b9050919050565b6107378161071c565b811461074257600080fd5b50565b6000813590506107548161072e565b92915050565b6000602082840312156107705761076f6106f2565b5b600061077e84828501610745565b91505092915050565b6000819050919050565b61079a81610787565b82525050565b60006020820190506107b56000830184610791565b92915050565b6107c481610787565b81146107cf57600080fd5b50565b6000813590506107e1816107bb565b92915050565b6000602082840312156107fd576107fc6106f2565b5b600061080b848285016107d2565b91505092915050565b600063ffffffff82169050919050565b61082d81610814565b811461083857600080fd5b50565b60008135905061084a81610824565b92915050565b60008060408385031215610867576108666106f2565b5b60006108758582860161083b565b9250506020610886858286016107d2565b9150509250929050565b61089981610787565b82525050565b6108a881610814565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156108e85780820151818401526020810190506108cd565b838111156108f7576000848401525b50505050565b6000601f19601f8301169050919050565b6000610919826108ae565b61092381856108b9565b93506109338185602086016108ca565b61093c816108fd565b840191505092915050565b600060608301600083015161095f6000860182610890565b506020830151610972602086018261089f565b506040830151848203604086015261098a828261090e565b9150508091505092915050565b600060208201905081810360008301526109b18184610947565b905092915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6109fb826108fd565b810181811067ffffffffffffffff82111715610a1a57610a196109c3565b5b80604052505050565b6000610a2d6106e8565b9050610a3982826109f2565b919050565b600067ffffffffffffffff821115610a5957610a586109c3565b5b610a62826108fd565b9050602081019050919050565b82818337600083830152505050565b6000610a91610a8c84610a3e565b610a23565b905082815260208101848484011115610aad57610aac6109be565b5b610ab8848285610a6f565b509392505050565b600082601f830112610ad557610ad46109b9565b5b8135610ae5848260208601610a7e565b91505092915050565b60008060008060808587031215610b0857610b076106f2565b5b6000610b16878288016107d2565b9450506020610b278782880161083b565b935050604085013567ffffffffffffffff811115610b4857610b476106f7565b5b610b5487828801610ac0565b925050606085013567ffffffffffffffff811115610b7557610b746106f7565b5b610b8187828801610ac0565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610bd457607f821691505b60208210811415610be857610be7610b8d565b5b50919050565b600082825260208201905092915050565b6000610c0a826108ae565b610c148185610bee565b9350610c248185602086016108ca565b610c2d816108fd565b840191505092915050565b6000606082019050610c4d6000830186610791565b610c5a6020830185610791565b8181036040830152610c6c8184610bff565b9050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610cb082610787565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610ce357610ce2610c76565b5b600182019050919050565b600081905092915050565b6000610d04826108ae565b610d0e8185610cee565b9350610d1e8185602086016108ca565b80840191505092915050565b6000610d368284610cf9565b915081905092915050565b6000604082019050610d566000830185610791565b8181036020830152610d688184610bff565b9050939250505056fea264697066735822122098a78c048a00b8794a9509dcb7a66d4ba197be12c71f75ae2264b5a67c34cd4b64736f6c634300080a0033",
225 | "linkReferences": {},
226 | "deployedLinkReferences": {}
227 | }
228 |
--------------------------------------------------------------------------------
/frontend/constants/index.js:
--------------------------------------------------------------------------------
1 | export * from './urls'
2 |
3 | export const CONTRACT_ADDRESS = process.env.NEXT_PUBLIC_CONTRACT_ADDRESS;
4 | export const CONTRACT_OWNER_ADDRESS = process.env.NEXT_PUBLIC_CONTRACT_OWNER_ADDRESS;
5 | export const PROJECT_ID = process.env.NEXT_PUBLIC_PROJECT_ID;
6 | export const PROJECT_SECRET = process.env.NEXT_PUBLIC_PROJECT_SECRET;
7 | export const IPFS_URL = "https://crowdfunding1.infura-ipfs.io/ipfs/"
--------------------------------------------------------------------------------
/frontend/constants/urls.js:
--------------------------------------------------------------------------------
1 | export const urls = {
2 | home: "/",
3 | admin: "/admin",
4 | pastOrders: "/my-orders"
5 | }
--------------------------------------------------------------------------------
/frontend/context/MainContext.js:
--------------------------------------------------------------------------------
1 | import { ethers } from "ethers";
2 | import { createContext, useState } from "react";
3 | import { CONTRACT_ADDRESS, CONTRACT_OWNER_ADDRESS } from "../constants";
4 | import ContractABI from "../constants/Ecommerce.json";
5 |
6 | export const MainContext = createContext("");
7 |
8 | export const MainProvider = ({ children }) => {
9 | const [accountAddress, setAccountAddress] = useState("");
10 | const [currentBlock, setCurrentBlock] = useState(0)
11 |
12 | const isAdmin = () => {
13 | if(!accountAddress) return false;
14 | if(CONTRACT_OWNER_ADDRESS === accountAddress){
15 | return true;
16 | }else{
17 | return false;
18 | }
19 | }
20 |
21 | const requestContract = async () => {
22 | await window.ethereum.request({ method: "eth_requestAccounts" });
23 | const provider = new ethers.providers.Web3Provider(window.ethereum);
24 | const signer = provider.getSigner();
25 |
26 | const contract = new ethers.Contract(
27 | CONTRACT_ADDRESS,
28 | ContractABI.abi,
29 | signer
30 | );
31 | const blockNumber = await provider.getBlockNumber();
32 | setCurrentBlock(blockNumber)
33 |
34 | return contract;
35 | }
36 |
37 | return (
38 |
47 | {children}
48 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/frontend/data/carouselData.js:
--------------------------------------------------------------------------------
1 | export const carouselData = [
2 | {imageSrc:'https://rukminim1.flixcart.com/flap/3376/560/image/d117a62eb5fbb8e1.jpg?q=50'},
3 | {imageSrc:'https://rukminim1.flixcart.com/flap/3376/560/image/57267a180af306fe.jpg?q=50'},
4 | {imageSrc:'https://rukminim1.flixcart.com/flap/3376/560/image/ae9966569097a8b7.jpg?q=50'},
5 | {imageSrc:'https://rukminim1.flixcart.com/flap/3376/560/image/f6202f13b6f89b03.jpg?q=50'}
6 | ]
--------------------------------------------------------------------------------
/frontend/data/dropdownData.js:
--------------------------------------------------------------------------------
1 | export const categories = [
2 | { label: "Mobiles", value: "mobile" },
3 | { label: "Fashion", value: "fashion" },
4 | { label: "Television", value: "television" },
5 | { label: "Electronics", value: "electronics" },
6 | { label: "Laptop", value: "laptop" },
7 | { label: "Camera", value: "camera" },
8 | { label: "Toys", value: "toys" },
9 | ];
10 |
11 | const getPath = (name) => {
12 | const PATH = "/images/categories/";
13 | return `${PATH}${name}_img.webp`;
14 | };
15 | export const homePageCategories = [
16 | {
17 | imgSrc: getPath("all"),
18 | text: "All",
19 | url: "all",
20 | },
21 | {
22 | imgSrc: getPath("mobile"),
23 | text: "Mobile",
24 | url: "mobile",
25 | },
26 | {
27 | imgSrc: getPath("clothes"),
28 | text: "Fashion",
29 | url: "fashion",
30 | },
31 | {
32 | imgSrc: getPath("television"),
33 | text: "Electronics",
34 | url: "electronics",
35 | },
36 | {
37 | imgSrc: getPath("laptops"),
38 | text: "Laptop",
39 | url: "laptop",
40 | },
41 | {
42 | imgSrc: getPath("camera"),
43 | text: "Camera",
44 | url: "camera",
45 | },
46 | {
47 | imgSrc: getPath("toys"),
48 | text: "Beauty, Toys & More",
49 | url: "toys",
50 | },
51 | ];
52 |
--------------------------------------------------------------------------------
/frontend/data/index.js:
--------------------------------------------------------------------------------
1 | export * from "./navData";
2 | export * from './dropdownData'
3 | export * from './carouselData'
4 |
--------------------------------------------------------------------------------
/frontend/data/navData.js:
--------------------------------------------------------------------------------
1 | import { TbLayoutDashboard } from "react-icons/tb";
2 | import { HiTemplate } from "react-icons/hi";
3 | import { AiFillCrown } from "react-icons/ai";
4 | import { urls } from "../constants";
5 |
6 | export const navLinks = [
7 | {
8 | title: "Dashboard",
9 | link: urls.home,
10 | icon: ,
11 | },
12 | {
13 | title: "Your Past Orders",
14 | link: urls.pastOrders,
15 | icon: ,
16 | },
17 | {
18 | title: "Admin",
19 | link: urls.admin,
20 | icon: ,
21 | },
22 | ];
23 |
--------------------------------------------------------------------------------
/frontend/layouts/MainLayout.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Head from "next/head";
3 | import { ThemeProvider } from "@material-tailwind/react";
4 |
5 | import Navbar from "../components/navbar/Navbar";
6 |
7 | export default function MainLayout({ metaTitle, metaDescription, addPM=true, children }) {
8 | return (
9 |
10 |
11 |
{metaTitle}
12 |
13 |
14 |
15 |
18 | {children}
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | swcMinify: true,
5 | }
6 |
7 | module.exports = nextConfig
8 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@material-tailwind/react": "^1.2.3",
13 | "ethers": "^5.7.0",
14 | "ipfs-http-client": "^57.0.3",
15 | "next": "12.2.5",
16 | "react": "18.2.0",
17 | "react-dom": "18.2.0",
18 | "react-icons": "^4.4.0",
19 | "react-toastify": "^9.0.8",
20 | "react-tsparticles": "^2.2.4",
21 | "tsparticles": "^2.2.4"
22 | },
23 | "devDependencies": {
24 | "autoprefixer": "^10.4.8",
25 | "eslint": "8.23.0",
26 | "eslint-config-next": "12.2.5",
27 | "postcss": "^8.4.16",
28 | "tailwindcss": "^3.1.8"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/pages/404.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ErrorPage from "../components/404-page/ErrorPage";
3 |
4 | export default function WrongPage() {
5 | return (
6 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/pages/[productid].js:
--------------------------------------------------------------------------------
1 | import { Button } from "@material-tailwind/react";
2 | import { ethers } from "ethers";
3 | import React, { useContext, useState } from "react";
4 | import { AiOutlineArrowRight } from "react-icons/ai";
5 | import ProductDetail from "../components/product-details/ProductDetail";
6 | import { CONTRACT_ADDRESS, urls } from "../constants";
7 | import ContractABI from "../constants/Ecommerce.json";
8 | import { MainContext } from "../context/MainContext";
9 | import MainLayout from "../layouts/MainLayout";
10 | import { ToastContainer, toast } from "react-toastify";
11 | import "react-toastify/dist/ReactToastify.css";
12 | import { useRouter } from "next/router";
13 |
14 | export default function Productid({ ProductIdData }) {
15 | const router = useRouter();
16 | const { accountAddress, requestContract } = useContext(MainContext);
17 | const [quantityInput, setQuantityInput] = useState("");
18 | const [open, setOpen] = useState(false);
19 |
20 | const transferFund = async () => {
21 | try {
22 | toast.info("Wait...");
23 | const contract = await requestContract();
24 |
25 | const transaction = await contract.buyProduct(ProductIdData.productId, {
26 | value: ethers.utils.parseEther(ProductIdData.price),
27 | });
28 | toast.promise(transaction.wait(), {
29 | pending: "Wait...",
30 | success: "Product Bought Successfully! 👌",
31 | error: "Some Error Occured. 🤯",
32 | });
33 | await transaction.wait();
34 | } catch (error) {
35 | console.log(error);
36 | toast.error("Some Error Occured. 🤯");
37 | }
38 | };
39 |
40 | const updateProductByAdmin = async () => {
41 | try {
42 | if (!quantityInput) {
43 | toast.error("Enter Quantity Value...");
44 | return;
45 | }
46 | setOpen(false);
47 | toast.info("Wait...");
48 |
49 | const contract = await requestContract();
50 | const tx = await contract.updateQuantity(
51 | quantityInput,
52 | ProductIdData.productId
53 | );
54 | toast.promise(tx.wait(), {
55 | pending: "Wait...",
56 | success: "Product Quantity Updated Successfully! 👌",
57 | error: "Some Error Occured. 🤯",
58 | });
59 | await tx.wait();
60 | setQuantityInput("");
61 | router.push(urls.pastOrders);
62 | } catch (error) {
63 | console.log(error);
64 | toast.error("Some Error Occured. Please try again 🤯");
65 | }
66 | };
67 |
68 | return (
69 |
70 |
71 |
82 | {accountAddress ? (
83 | <>
84 |
93 | >
94 | ) : (
95 | "Connect Wallet to Buy"
96 | )}
97 |
98 |
99 | );
100 | }
101 |
102 | export async function getStaticPaths() {
103 | const RPC_URL = process.env.NEXT_PUBLIC_POLYGON_RPC_URL;
104 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
105 |
106 | const contract = new ethers.Contract(
107 | CONTRACT_ADDRESS,
108 | ContractABI.abi,
109 | provider
110 | );
111 |
112 | const getAllProducts = contract.filters.productAdded();
113 | const AllProducts = await contract.queryFilter(getAllProducts);
114 |
115 | return {
116 | paths: AllProducts.map((e) => ({
117 | params: {
118 | productid: e.args._productId.toString(),
119 | },
120 | })),
121 | fallback: "blocking",
122 | };
123 | }
124 |
125 | export async function getStaticProps(context) {
126 | const productId = parseInt(context.params.productid);
127 | const RPC_URL = process.env.NEXT_PUBLIC_POLYGON_RPC_URL;
128 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
129 |
130 | const contract = new ethers.Contract(
131 | CONTRACT_ADDRESS,
132 | ContractABI.abi,
133 | provider
134 | );
135 |
136 | const ProductData = await contract.getProduct(productId);
137 | const ProductIdData = {
138 | productId: parseInt(productId),
139 | price: ethers.utils.formatEther(ProductData.price),
140 | quantity: parseInt(ProductData.quantity),
141 | metadata: ProductData.metadata,
142 | };
143 |
144 | return {
145 | props: {
146 | ProductIdData,
147 | },
148 | };
149 | }
150 |
--------------------------------------------------------------------------------
/frontend/pages/_app.js:
--------------------------------------------------------------------------------
1 | import { MainProvider } from "../context/MainContext";
2 | import "../styles/globals.css";
3 |
4 | function MyApp({ Component, pageProps }) {
5 | return (
6 |
7 |
8 |
9 | );
10 | }
11 |
12 | export default MyApp;
13 |
--------------------------------------------------------------------------------
/frontend/pages/admin.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import ErrorPage from "../components/404-page/ErrorPage";
3 | import Admin from "../components/admin/Admin";
4 | import AdminDashboard from "../components/admin/AdminDashboard";
5 | import TabComp from "../components/admin/TabComp";
6 | import { MainContext } from "../context/MainContext";
7 | import MainLayout from "../layouts/MainLayout";
8 |
9 | export default function AdminPage() {
10 | const { accountAddress, isAdmin } = useContext(MainContext);
11 | const tabData = [
12 | {
13 | label: "Add Product",
14 | value: "addproduct",
15 | desc:
16 | },
17 | {
18 | label: "Admin Dashboard",
19 | value: "admindashboard",
20 | desc:
21 | },
22 | ];
23 |
24 |
25 |
26 | return (
27 |
28 | {accountAddress
29 | ? isAdmin()
30 | ?
31 |
32 |
33 | :
34 | : }
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/frontend/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 |
--------------------------------------------------------------------------------
/frontend/pages/index.js:
--------------------------------------------------------------------------------
1 | import { CONTRACT_ADDRESS } from "../constants";
2 | import ContractABI from "../constants/Ecommerce.json";
3 | import MainLayout from "../layouts/MainLayout";
4 | import { ethers } from "ethers";
5 | import { useState, useEffect } from "react";
6 | import Card1 from "../subcomponents/card/Card1";
7 | import Categories from "../components/categories/Categories";
8 | import { Typography } from "@material-tailwind/react";
9 |
10 | export default function Home({
11 | AllData,
12 | MobileData,
13 | FashionData,
14 | ElectronicData,
15 | LaptopData,
16 | CameraData,
17 | ToysData,
18 | }) {
19 | const [isLoading, setIsLoading] = useState(false);
20 | const [selectedCategory, setSelectedCategory] = useState("all");
21 | const [selectedCategoryData, setSelectedCategoryData] = useState([]);
22 | useEffect(() => {
23 | switch (selectedCategory) {
24 | case "all":
25 | setSelectedCategoryData(AllData);
26 | break;
27 | case "mobile":
28 | setSelectedCategoryData(MobileData);
29 | break;
30 | case "fashion":
31 | setSelectedCategoryData(FashionData);
32 | break;
33 | case "electronics":
34 | setSelectedCategoryData(ElectronicData);
35 | break;
36 | case "laptop":
37 | setSelectedCategoryData(LaptopData);
38 | break;
39 | case "camera":
40 | setSelectedCategoryData(CameraData);
41 | break;
42 | case "toys":
43 | setSelectedCategoryData(ToysData);
44 | break;
45 | default:
46 | setSelectedCategoryData(AllData);
47 | break;
48 |
49 | }
50 | }, [selectedCategory]);
51 |
52 | return (
53 |
54 |
55 | {selectedCategory.toUpperCase()}
56 |
57 | {selectedCategoryData.length
58 | ? selectedCategoryData.map((item, index) => (
59 |
67 | ))
68 | : !selectedCategoryData.length && !isLoading
69 | ? "No Product Found"
70 | : "Loading..."}
71 |
72 |
73 | );
74 | }
75 |
76 | export async function getStaticProps() {
77 | const RPC_URL = process.env.NEXT_PUBLIC_POLYGON_RPC_URL;
78 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
79 |
80 | const contract = new ethers.Contract(
81 | CONTRACT_ADDRESS,
82 | ContractABI.abi,
83 | provider
84 | );
85 |
86 | const getEventData = async (category) => {
87 | const getAllProducts = contract.filters.productAdded(category);
88 | const AllProducts = await contract.queryFilter(getAllProducts);
89 | const mappedData = AllProducts.map((e) => {
90 | const args = e.args;
91 | return {
92 | metadata: args._metadata,
93 | productId: parseInt(args._productId),
94 | price: ethers.utils.formatEther(args._price),
95 | timeStamp: parseInt(args._timestamp),
96 | };
97 | });
98 | return mappedData;
99 | };
100 |
101 | const AllData = await getEventData(null);
102 | const MobileData = await getEventData("mobile");
103 | const FashionData = await getEventData("fashion");
104 | const ElectronicData = await getEventData("electronics");
105 | const LaptopData = await getEventData("laptop");
106 | const CameraData = await getEventData("camera");
107 | const ToysData = await getEventData("toys");
108 |
109 | return {
110 | props: {
111 | AllData,
112 | MobileData,
113 | FashionData,
114 | ElectronicData,
115 | LaptopData,
116 | CameraData,
117 | ToysData,
118 | },
119 | };
120 | }
121 |
--------------------------------------------------------------------------------
/frontend/pages/my-orders.js:
--------------------------------------------------------------------------------
1 | import { ethers } from "ethers";
2 | import React, { useState, useEffect, useContext } from "react";
3 | import ErrorPage from "../components/404-page/ErrorPage";
4 | import { MainContext } from "../context/MainContext";
5 | import MainLayout from "../layouts/MainLayout";
6 | import Card1 from "../subcomponents/card/Card1";
7 |
8 | export default function Myorders() {
9 | const { accountAddress, currentBlock, requestContract } = useContext(MainContext);
10 | const [myProducts, setMyProducts] = useState([]);
11 | const [isLoading, setIsLoading] = useState(false);
12 |
13 | useEffect(() => {
14 | const Request = async () => {
15 | if (accountAddress) {
16 | try {
17 | setIsLoading(true);
18 | const contract = await requestContract();
19 |
20 | const getBoughtEvents = contract.filters.productBought(accountAddress);
21 | const AllBoughtProducts = await contract.queryFilter(
22 | getBoughtEvents,
23 | currentBlock - 1000,
24 | currentBlock
25 | );
26 | // console.log(AllBoughtProducts);
27 | const MyData = AllBoughtProducts.map((e) => {
28 | const args = e.args;
29 | return {
30 | metadata: args.metadata,
31 | productId: parseInt(args._productId),
32 | price: ethers.utils.formatEther(args.price),
33 | timeStamp: parseInt(args.timestamp),
34 | };
35 | });
36 | setMyProducts(MyData);
37 | setIsLoading(false);
38 | } catch (error) {
39 | setIsLoading(false);
40 | console.log("error....", error);
41 | }
42 | }
43 | };
44 | Request();
45 | }, [accountAddress]);
46 |
47 | return (
48 |
49 | {accountAddress ? (
50 |
51 | {myProducts.length
52 | ? myProducts.map((item, index) => (
53 |
60 | ))
61 | : !myProducts.length && !isLoading
62 | ?
68 | : "Loading..."}
69 |
70 | ) : (
71 |
77 | )}
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/frontend/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/images/404-image.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/404-image.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/all_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/all_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/camera_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/camera_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/clothes_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/clothes_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/laptops_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/laptops_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/mobile_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/mobile_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/television_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/television_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/categories/toys_img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/categories/toys_img.webp
--------------------------------------------------------------------------------
/frontend/public/images/connect-wallet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/connect-wallet.png
--------------------------------------------------------------------------------
/frontend/public/images/ipad_image.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/ipad_image.webp
--------------------------------------------------------------------------------
/frontend/public/images/login-img.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/login-img.webp
--------------------------------------------------------------------------------
/frontend/public/images/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SachinCoder1/Ecommerce-DAPP/187746ee50e4522ba34a3bde37437919904b6510/frontend/public/images/logo.jpg
--------------------------------------------------------------------------------
/frontend/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 |
6 |
7 | .categoryCont {
8 | display:flex;
9 | justify-content:space-evenly;
10 | align-items:center;
11 | max-width:100vw;
12 | background-color:#fff;
13 | border-bottom:1px solid rgba(0,0,0,0.2);
14 | }
15 |
16 | .cateBox {
17 | cursor:pointer;
18 | text-align:center;
19 | display:flex;
20 | flex-direction:column;
21 | justify-content:center;
22 | align-items:center;
23 | padding:10px 10px;
24 | }
25 |
26 | .cateBox img{
27 | width:50%;
28 | }
29 | .cateBox img span:hover{
30 | color:#0C73EB;
31 | }
32 |
33 | @media (max-width:768px) {
34 | .cateBox {
35 | padding:10px 2px;
36 | }
37 |
38 | .cateBox:nth-child(7){
39 | display:none;
40 | }
41 | .cateBox:nth-child(8){
42 | display:none;
43 | }
44 | .cateBox:nth-child(9){
45 | display:none;
46 | }
47 |
48 | .cateBox span{
49 | display:none;
50 | }
51 | .cateBox img{
52 | width:70%;
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/frontend/subcomponents/card/Card1.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | Card,
3 | CardHeader,
4 | CardBody,
5 | CardFooter,
6 | Typography,
7 | Button,
8 | } from "@material-tailwind/react";
9 | import { FaEthereum } from "react-icons/fa";
10 | import { BsPersonCheckFill } from "react-icons/bs";
11 | import { AiOutlineArrowRight } from "react-icons/ai";
12 | import { MdDateRange } from "react-icons/md";
13 | import Link from "next/link";
14 | import { timeConverter } from "../../utils/DateConverter";
15 | import { useRouter } from "next/router";
16 | import { IPFS_URL } from "../../constants";
17 | import { useContext, useState, useEffect } from "react";
18 | import { MainContext } from "../../context/MainContext";
19 |
20 | export default function Card1({ metadata, price, publishedDate, productId, selectedCategory }) {
21 | const router = useRouter();
22 | const { isAdmin } = useContext(MainContext);
23 | const [parsedMetaData, setParsedMetaData] = useState({})
24 | useEffect(() => {
25 |
26 | const fetchMetaData = async() => {
27 | const data = await fetch(`${IPFS_URL}${metadata}`);
28 | const JSONData = await data.json();
29 | setParsedMetaData(JSONData);
30 | }
31 | fetchMetaData();
32 |
33 | }, [price, selectedCategory])
34 |
35 | return (
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | {parsedMetaData?.title}
45 |
46 | {/* {description.slice(0, 80)}... */}
47 |
48 |
49 |
50 |
51 | {price} ETH
52 |
53 | {/*
58 |
59 | {address && address.slice(0, 6)}...{address.slice(address.length - 4)}
60 | */}
61 |
62 |
63 |
64 |
70 |
71 | {isAdmin() && (
72 |
77 |
78 | {timeConverter(publishedDate)}
79 |
80 | )}
81 |
82 |
83 | );
84 | }
85 |
--------------------------------------------------------------------------------
/frontend/subcomponents/logo/Logo.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export default function Logo() {
4 | return (
5 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/subcomponents/modal/Modal.jsx:
--------------------------------------------------------------------------------
1 | import { Fragment, useState } from "react";
2 | import {
3 | Button,
4 | Dialog,
5 | DialogHeader,
6 | DialogBody,
7 | DialogFooter,
8 | } from "@material-tailwind/react";
9 |
10 | export default function Modal({ text, open, setOpen, children }) {
11 | // const [open, setOpen] = useState(false);
12 |
13 | const handleOpen = () => setOpen(!open);
14 |
15 | return (
16 |
17 |
20 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/frontend/subcomponents/particles-ts/TsParticles.jsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 | import Particles from "react-tsparticles";
3 | import tsConfig from "../../configs/tsConfig.json";
4 | import { loadFull } from "tsparticles";
5 |
6 | export default function TsParticles() {
7 | const particlesInit = async (main) => {
8 | await loadFull(main);
9 | };
10 |
11 | return (
12 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const withMT = require("@material-tailwind/react/utils/withMT");
2 | module.exports = withMT({
3 | content: [
4 | "./pages/**/*.{js,ts,jsx,tsx}",
5 | "./components/**/*.{js,ts,jsx,tsx}",
6 | "./subcomponents/**/*.{js,ts,jsx,tsx}",
7 | "./layouts/**/*.{js,ts,jsx,tsx}",
8 | ],
9 | theme: {
10 | colors: {
11 | primary: {
12 | // DEFAULT: "#76528BFF",
13 | DEFAULT: "#5F4B8BFF",
14 | }
15 | },
16 | },
17 | plugins: [],
18 | });
19 |
--------------------------------------------------------------------------------
/frontend/utils/DateConverter.js:
--------------------------------------------------------------------------------
1 | export const timeConverter = (UNIX_timestamp) => {
2 | var a = new Date(UNIX_timestamp * 1000);
3 | var months = [
4 | "Jan",
5 | "Feb",
6 | "Mar",
7 | "Apr",
8 | "May",
9 | "Jun",
10 | "Jul",
11 | "Aug",
12 | "Sep",
13 | "Oct",
14 | "Nov",
15 | "Dec",
16 | ];
17 | var year = a.getFullYear();
18 | var month = months[a.getMonth()];
19 | var date = a.getDate() < 10 ? "0" + a.getDate() : a.getDate();
20 | var time = date + " " + month + " " + year;
21 | return time;
22 | };
23 |
--------------------------------------------------------------------------------