├── front-end ├── src │ ├── pages │ │ ├── home │ │ │ ├── home.css │ │ │ └── Home.jsx │ │ ├── mint │ │ │ ├── mint.css │ │ │ └── mint.jsx │ │ ├── ItemOwner │ │ │ ├── ItemOwner.css │ │ │ └── ItemOwner.jsx │ │ ├── index.js │ │ ├── login │ │ │ ├── Login.jsx │ │ │ └── login.css │ │ ├── profile │ │ │ ├── Profile.jsx │ │ │ └── profile.css │ │ ├── register │ │ │ ├── Register.jsx │ │ │ └── register.css │ │ ├── create │ │ │ ├── Create.jsx │ │ │ └── create.css │ │ ├── item │ │ │ ├── item.css │ │ │ └── Item.jsx │ │ ├── bidItem │ │ │ ├── BidItem.css │ │ │ └── BidItem.jsx │ │ └── DetailItemOwner │ │ │ ├── DetailItemOwner.css │ │ │ └── DetailItemOwner.jsx │ ├── components │ │ ├── Tabs │ │ │ ├── Tabs.css │ │ │ └── Tabs.jsx │ │ ├── AllNFTs │ │ │ ├── AllNFTs.css │ │ │ └── AllNFTs.jsx │ │ ├── NFTsForSale │ │ │ ├── NFTsForSale.css │ │ │ └── NFTsForSale.jsx │ │ ├── NFTsForVote │ │ │ ├── NFTsForVote.css │ │ │ └── NFTsForVote.jsx │ │ ├── TabComponents │ │ │ ├── AllNFTs │ │ │ │ ├── AllNFTs.css │ │ │ │ └── AllNFTs.jsx │ │ │ ├── NFTsForSale │ │ │ │ ├── NFTsForSale.css │ │ │ │ └── NFTsForSale.jsx │ │ │ └── NFTsForVote │ │ │ │ ├── NFTsForVote.css │ │ │ │ └── NFTsForVote.jsx │ │ ├── index.js │ │ ├── footer │ │ │ ├── Footer.jsx │ │ │ └── footer.css │ │ ├── bids │ │ │ ├── bids.css │ │ │ └── Bids.jsx │ │ ├── ListItemOwner │ │ │ ├── ListItemOwner.css │ │ │ └── ListItemOwner.jsx │ │ ├── navbar │ │ │ ├── Navbar.jsx │ │ │ └── navbar.css │ │ ├── nftMint │ │ │ ├── nftMint.css │ │ │ └── nftMint.jsx │ │ ├── header │ │ │ ├── Header.jsx │ │ │ └── header.css │ │ └── Pagination │ │ │ ├── Pagination.css │ │ │ └── Pagination.jsx │ ├── assets │ │ ├── Image.png │ │ ├── bids1.png │ │ ├── bids2.png │ │ ├── bids3.png │ │ ├── bids4.png │ │ ├── bids5.png │ │ ├── bids6.png │ │ ├── bids7.png │ │ ├── bids8.png │ │ ├── coin.png │ │ ├── item1.png │ │ ├── logo.png │ │ ├── ss1.png │ │ ├── ss2.png │ │ ├── ss3.png │ │ ├── ss4.png │ │ ├── loading.gif │ │ ├── profile.jpg │ │ ├── seller1.jpg │ │ ├── seller2.png │ │ ├── seller3.png │ │ ├── seller4.png │ │ ├── seller5.png │ │ ├── seller6.jpg │ │ ├── verify.png │ │ ├── 4f.drawio.png │ │ └── profile_banner.png │ ├── index.js │ ├── index.css │ ├── App.js │ ├── constant │ │ └── constant.js │ ├── test │ │ └── test.html │ └── App.css ├── public │ ├── _redirects │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ ├── index.html │ └── reset.css ├── README.md └── package.json ├── contract ├── README.md ├── Move.lock ├── Move.toml └── sources │ ├── four_future_nft.move │ ├── auction_lib.move │ └── marketplace.move └── README.md /front-end/src/pages/home/home.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/pages/mint/mint.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/components/Tabs/Tabs.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/pages/ItemOwner/ItemOwner.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/components/AllNFTs/AllNFTs.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 2 | -------------------------------------------------------------------------------- /front-end/src/components/NFTsForSale/NFTsForSale.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/components/NFTsForVote/NFTsForVote.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/components/TabComponents/AllNFTs/AllNFTs.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/components/TabComponents/NFTsForSale/NFTsForSale.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/src/components/TabComponents/NFTsForVote/NFTsForVote.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front-end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /front-end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/public/favicon.ico -------------------------------------------------------------------------------- /front-end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/public/logo192.png -------------------------------------------------------------------------------- /front-end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/public/logo512.png -------------------------------------------------------------------------------- /front-end/src/assets/Image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/Image.png -------------------------------------------------------------------------------- /front-end/src/assets/bids1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids1.png -------------------------------------------------------------------------------- /front-end/src/assets/bids2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids2.png -------------------------------------------------------------------------------- /front-end/src/assets/bids3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids3.png -------------------------------------------------------------------------------- /front-end/src/assets/bids4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids4.png -------------------------------------------------------------------------------- /front-end/src/assets/bids5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids5.png -------------------------------------------------------------------------------- /front-end/src/assets/bids6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids6.png -------------------------------------------------------------------------------- /front-end/src/assets/bids7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids7.png -------------------------------------------------------------------------------- /front-end/src/assets/bids8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/bids8.png -------------------------------------------------------------------------------- /front-end/src/assets/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/coin.png -------------------------------------------------------------------------------- /front-end/src/assets/item1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/item1.png -------------------------------------------------------------------------------- /front-end/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/logo.png -------------------------------------------------------------------------------- /front-end/src/assets/ss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/ss1.png -------------------------------------------------------------------------------- /front-end/src/assets/ss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/ss2.png -------------------------------------------------------------------------------- /front-end/src/assets/ss3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/ss3.png -------------------------------------------------------------------------------- /front-end/src/assets/ss4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/ss4.png -------------------------------------------------------------------------------- /front-end/src/assets/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/loading.gif -------------------------------------------------------------------------------- /front-end/src/assets/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/profile.jpg -------------------------------------------------------------------------------- /front-end/src/assets/seller1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/seller1.jpg -------------------------------------------------------------------------------- /front-end/src/assets/seller2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/seller2.png -------------------------------------------------------------------------------- /front-end/src/assets/seller3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/seller3.png -------------------------------------------------------------------------------- /front-end/src/assets/seller4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/seller4.png -------------------------------------------------------------------------------- /front-end/src/assets/seller5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/seller5.png -------------------------------------------------------------------------------- /front-end/src/assets/seller6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/seller6.jpg -------------------------------------------------------------------------------- /front-end/src/assets/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/verify.png -------------------------------------------------------------------------------- /front-end/src/assets/4f.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/4f.drawio.png -------------------------------------------------------------------------------- /front-end/src/assets/profile_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xalberto/AI-NFT-marketplace-sui/HEAD/front-end/src/assets/profile_banner.png -------------------------------------------------------------------------------- /front-end/src/pages/mint/mint.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {NFTMint, Header, } from '../../components' 3 | 4 | 5 | const Mint = () => { 6 | 7 | return
8 | 9 |
; 10 | }; 11 | 12 | export default Mint; 13 | -------------------------------------------------------------------------------- /front-end/src/pages/ItemOwner/ItemOwner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {ListItemOwner} from '../../components' 3 | 4 | 5 | const ItemOwner = () => { 6 | 7 | return
8 | 9 |
; 10 | }; 11 | 12 | export default ItemOwner; 13 | -------------------------------------------------------------------------------- /front-end/src/pages/home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Bids, Header,Tabs } from '../../components' 3 | 4 | 5 | const Home = () => { 6 | 7 | return
8 |
9 | {/* */} 10 | 11 |
; 12 | }; 13 | 14 | export default Home; 15 | -------------------------------------------------------------------------------- /front-end/src/components/index.js: -------------------------------------------------------------------------------- 1 | export {default as Navbar} from './navbar/Navbar'; 2 | export {default as Header} from './header/Header'; 3 | export {default as Bids} from './bids/Bids'; 4 | export {default as Footer} from './footer/Footer'; 5 | export {default as NFTMint} from './nftMint/nftMint'; 6 | export {default as ListItemOwner} from './ListItemOwner/ListItemOwner'; 7 | export {default as Tabs} from './Tabs/Tabs'; 8 | -------------------------------------------------------------------------------- /front-end/src/components/AllNFTs/AllNFTs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Bids } from './Bid'; // Import Bids component 3 | 4 | const AllNFTs = () => { 5 | return ( 6 |
7 | {/* Filter data based on status (1 and 2) */} 8 | 9 |
10 | ); 11 | }; 12 | 13 | export default AllNFTs; 14 | -------------------------------------------------------------------------------- /front-end/src/components/NFTsForSale/NFTsForSale.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Bids } from './Bid'; // Import Bids component 3 | 4 | const NFTsForVote = () => { 5 | const [dataWithVote functionality] = useState( /* filtered and vote logic */ ); 6 | 7 | return ( 8 |
9 | 10 |
11 | ); 12 | }; 13 | 14 | export default NFTsForVote; 15 | -------------------------------------------------------------------------------- /front-end/src/components/NFTsForVote/NFTsForVote.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Bids } from './Bid'; // Import Bids component 3 | 4 | const NFTsForVote = () => { 5 | const [dataWithVote functionality] = useState( /* filtered and vote logic */ ); 6 | 7 | return ( 8 |
9 | 10 |
11 | ); 12 | }; 13 | 14 | export default NFTsForVote; 15 | -------------------------------------------------------------------------------- /front-end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import { BrowserRouter } from "react-router-dom"; 6 | import { WalletProvider } from '@suiet/wallet-kit'; 7 | import '@suiet/wallet-kit/style.css'; 8 | 9 | 10 | ReactDOM.render( 11 | 12 | 13 | 14 | 15 | , 16 | document.getElementById('root') 17 | ); 18 | 19 | -------------------------------------------------------------------------------- /front-end/src/pages/index.js: -------------------------------------------------------------------------------- 1 | export {default as Home} from './home/Home'; 2 | export {default as Profile} from './profile/Profile'; 3 | export {default as Item} from './item/Item'; 4 | export {default as BidItem} from './bidItem/BidItem'; 5 | export {default as Create} from './create/Create'; 6 | export {default as Login} from './login/Login'; 7 | export {default as Register} from './register/Register'; 8 | export {default as Mint} from './mint/mint'; 9 | export {default as ItemOwner} from './ItemOwner/ItemOwner'; 10 | export {default as DetailItemOwner} from './DetailItemOwner/DetailItemOwner'; 11 | -------------------------------------------------------------------------------- /front-end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /front-end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | NFT MarketPlace 16 | 17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /contract/README.md: -------------------------------------------------------------------------------- 1 | # Contract Docs 2 | 3 | ## Request Test Token (DevNet) 4 | ``` 5 | curl --location --request POST 'https://faucet.devnet.sui.io/gas' \ 6 | --header 'Content-Type: application/json' \ 7 | --data-raw '{ 8 | "FixedAmountRequest": { 9 | "recipient": "" 10 | } 11 | }' 12 | ``` 13 | 14 | ## Publish Contract (DevNet) 15 | ``` 16 | sui client publish --gas-budget 500000000 --skip-dependency-verification 17 | ``` 18 | 19 | ## Call Function Mint NFT 20 | ``` 21 | sui client call --package --module four_future_nft --function mint_to_sender --args --gas-budget 500000000 22 | ``` 23 | 24 | ## Call Function Create MarketPlace 25 | ``` 26 | sui client call --package --module marketplace --function create --type-args 0x2::sui::SUI --gas-budget 500000000 27 | ``` 28 | -------------------------------------------------------------------------------- /front-end/src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap'); 2 | 3 | :root { 4 | --font-family: 'Poppins', sans-serif; 5 | 6 | --gradient2: linear-gradient(89.97deg, #EB1484 1.84%, #c81cc5 102.67%); 7 | --primary-btn: linear-gradient(101.12deg, #EB1484 27.35%, #C91CC3 99.99%, #C81CC5 100%, #C81CC5 100%); 8 | 9 | --primary-color: #EB1484; 10 | --secondary-color: #c81cc5; 11 | 12 | --color-bg: #24252d; 13 | --color-card : #2A2D3A; 14 | --color-footer : #24252D; 15 | } 16 | /* ===== Scrollbar CSS ===== */ 17 | /* Firefox */ 18 | * { 19 | scrollbar-width: auto; 20 | scrollbar-color: #2A2D3A #ffffff; 21 | } 22 | 23 | /* Chrome, Edge, and Safari */ 24 | *::-webkit-scrollbar { 25 | width: 14px; 26 | } 27 | 28 | *::-webkit-scrollbar-track { 29 | background: transparent; 30 | } 31 | 32 | *::-webkit-scrollbar-thumb { 33 | background: var(--color-card); 34 | border-radius: 10px; 35 | border: 3px none #ffffff; 36 | } -------------------------------------------------------------------------------- /front-end/src/pages/login/Login.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './login.css' 3 | import {Link} from 'react-router-dom' 4 | const Login = () => { 5 | 6 | 7 | return ( 8 |
9 |
10 |

Login

11 |
12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 |
27 |
28 |
29 |
30 | ) 31 | }; 32 | 33 | export default Login; 34 | -------------------------------------------------------------------------------- /contract/Move.lock: -------------------------------------------------------------------------------- 1 | # @generated by Move, please check-in and do not edit manually. 2 | 3 | [move] 4 | version = 1 5 | manifest_digest = "C32418A329F67841D311BD3A77035FF8458E52F6BC8B905CEFB944AD476C8508" 6 | deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" 7 | dependencies = [ 8 | { name = "Sui" }, 9 | ] 10 | 11 | [[move.package]] 12 | name = "MoveStdlib" 13 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/devnet", subdir = "crates/sui-framework/packages/move-stdlib" } 14 | 15 | [[move.package]] 16 | name = "Sui" 17 | source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/devnet", subdir = "crates/sui-framework/packages/sui-framework" } 18 | 19 | dependencies = [ 20 | { name = "MoveStdlib" }, 21 | ] 22 | 23 | [move.toolchain-version] 24 | compiler-version = "1.23.0" 25 | edition = "legacy" 26 | flavor = "sui" 27 | 28 | [env] 29 | 30 | [env.devnet] 31 | chain-id = "f1c1a0c0" 32 | original-published-id = "0x5903caf0c870733e5f5a2557f4df12896480bc678b06067042d997a2a946424c" 33 | latest-published-id = "0x5903caf0c870733e5f5a2557f4df12896480bc678b06067042d997a2a946424c" 34 | published-version = "1" 35 | -------------------------------------------------------------------------------- /front-end/src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import {Navbar,Footer} from './components' 3 | import {Home,Profile,Item, Create,Login,Register,Mint,ItemOwner,DetailItemOwner, BidItem} from './pages' 4 | import { Routes, Route } from "react-router-dom"; 5 | 6 | function App() { 7 | 8 | return ( 9 |
10 | 11 | 12 | } /> 13 | } /> 14 | } /> 15 | } /> 16 | } /> 17 | } /> 18 | } /> 19 | } /> 20 | } /> 21 | } /> 22 | 23 |
24 |
25 | ); 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /front-end/src/pages/profile/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './profile.css' 3 | import profile_banner from '../../assets/profile_banner.png' 4 | import profile_pic from '../../assets/profile.jpg' 5 | import Bids from '../../components/bids/Bids' 6 | 7 | const Profile = () => { 8 | 9 | return ( 10 |
11 |
12 |
13 | banner 14 |
15 |
16 | profile 17 |

James Bond

18 |
19 |
20 |
21 |
22 | 23 | 29 |
30 | 31 |
32 |
33 | ); 34 | }; 35 | 36 | export default Profile; 37 | -------------------------------------------------------------------------------- /front-end/src/components/Tabs/Tabs.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState } from "react"; 3 | import AllNFTs from "../TabComponents/AllNFTs/AllNFTs"; 4 | import NFTsForVote from "../TabComponents/NFTsForVote/NFTsForVote"; 5 | import NFTsForSale from "../TabComponents/NFTsForSale/NFTsForSale"; 6 | 7 | const Tabs = () => { 8 | const [activeTab, setActiveTab] = useState("tab2"); 9 | const handleTab1 = () => { 10 | setActiveTab("tab1"); 11 | }; 12 | const handleTab2 = () => { 13 | setActiveTab("tab2"); 14 | }; 15 | const handleTab3 = () => { 16 | setActiveTab("tab3"); 17 | }; 18 | 19 | 20 | return ( 21 |
22 | {/* Tab nav */} 23 |
    24 | {/*
  • All NFT
  • */} 25 |
  • Bid NFT
  • 26 |
  • Sale NFT
  • 27 |
28 |
29 | {activeTab === "tab1" ? : activeTab === "tab2" ?:} 30 |
31 |
32 | ); 33 | }; 34 | export default Tabs; -------------------------------------------------------------------------------- /front-end/README.md: -------------------------------------------------------------------------------- 1 |
2 |


NFT Marketplace

3 |
4 | 5 | # Description 6 | NFT Marketplace template for creation, sale, and purchase of digital art as NFTs. 7 | 8 | 9 | # Tech Used 10 | - Sui move smart contract 11 | - Sui move kiosk 12 | - react 13 | 14 | ## Live Preview 15 | [Demo](https://......netlify.app/) 16 | 17 | ## Build Setup 18 | 19 | ``` bash 20 | # clone project 21 | $ git clone https://github.com/nhatlapross/AI-NFT-marketplace 22 | 23 | # Go to front-end 24 | $ cd AI-NFT-marketplace 25 | $ cd front-end 26 | 27 | # install dependencies 28 | $ npm install 29 | 30 | # serve with host at localhost:8000 31 | $ npm start 32 | ``` 33 | 34 | # Screenshot 35 | !["React Movie App"](https://raw.githubusercontent.com/kasim393/NFT-Marketplace/main/src/assets/ss1.png) 36 | 37 | Google font: https://fonts.google.com/ 38 | 39 | FontAwesome : https://fontawesome.com/ 40 | 41 | Figma : https://uifreebies.net/figma/cryptoket-app-ui-kit-free 42 | 43 | 44 | ### Task 45 | - [x] Home page 46 | - [x] Detail page 47 | - [x] Login page 48 | - [x] Register page 49 | - [x] Create item page 50 | - [x] Profile page 51 | - [ ] Payment 52 | 53 | 54 | -------------------------------------------------------------------------------- /front-end/src/components/TabComponents/NFTsForVote/NFTsForVote.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Bids from '../../bids/Bids'; 3 | import * as constant from '../../../constant/constant'; 4 | 5 | const NFTsForVote = () => { 6 | const [bagData,setBagData] = useState(null); 7 | const [auctions,setAuctions] = useState(null); 8 | useEffect(()=> { 9 | LoadNFT(); 10 | }, []) 11 | 12 | useEffect(async()=> { 13 | const listResData = []; 14 | for(const au of auctions){ 15 | console.log(au); 16 | const data = await constant.client.call('sui_getObject', 17 | [au, 18 | { 19 | "showType": true, 20 | "showOwner": true, 21 | "showPreviousTransaction": true, 22 | "showContent": true, 23 | }]); 24 | listResData.push(data); 25 | } 26 | setBagData(listResData); 27 | console.log(bagData) 28 | 29 | }, [auctions]) 30 | 31 | async function LoadNFT(){ 32 | const listAuction = []; 33 | const listAu = await constant.client.call('suix_getDynamicFields',[constant.bidMarketBagID]); 34 | console.log(listAu); 35 | for(const au of listAu.data){ 36 | listAuction.push(au.name.value); 37 | console.log(au); 38 | } 39 | setAuctions(listAuction); 40 | } 41 | 42 | 43 | return ( 44 |
45 | 46 |
47 | ); 48 | }; 49 | 50 | export default NFTsForVote; 51 | -------------------------------------------------------------------------------- /front-end/public/reset.css: -------------------------------------------------------------------------------- 1 | /* Box sizing rules */ 2 | *, 3 | *::before, 4 | *::after { 5 | box-sizing: border-box; 6 | } 7 | 8 | /* Remove default margin */ 9 | body, 10 | h1, 11 | h2, 12 | h3, 13 | h4, 14 | p, 15 | figure, 16 | blockquote, 17 | dl, 18 | dd { 19 | margin: 0; 20 | } 21 | 22 | /* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */ 23 | ul[role='list'], 24 | ol[role='list'] { 25 | list-style: none; 26 | } 27 | 28 | /* Set core root defaults */ 29 | html:focus-within { 30 | scroll-behavior: smooth; 31 | } 32 | 33 | /* Set core body defaults */ 34 | body { 35 | min-height: 100vh; 36 | text-rendering: optimizeSpeed; 37 | line-height: 1.5; 38 | } 39 | 40 | /* A elements that don't have a class get default styles */ 41 | a:not([class]) { 42 | text-decoration-skip-ink: auto; 43 | } 44 | 45 | /* Make images easier to work with */ 46 | img, 47 | picture { 48 | max-width: 100%; 49 | display: block; 50 | } 51 | 52 | /* Inherit fonts for inputs and buttons */ 53 | input, 54 | button, 55 | textarea, 56 | select { 57 | font: inherit; 58 | } 59 | 60 | /* Remove all animations, transitions and smooth scroll for people that prefer not to see them */ 61 | @media (prefers-reduced-motion: reduce) { 62 | html:focus-within { 63 | scroll-behavior: auto; 64 | } 65 | 66 | *, 67 | *::before, 68 | *::after { 69 | animation-duration: 0.01ms !important; 70 | animation-iteration-count: 1 !important; 71 | transition-duration: 0.01ms !important; 72 | scroll-behavior: auto !important; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /front-end/src/components/TabComponents/NFTsForSale/NFTsForSale.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState,useEffect } from 'react'; 2 | import Bids from '../../bids/Bids'; // Import Bids component 3 | import * as constant from '../../../constant/constant'; 4 | 5 | const NFTsForSale = () => { 6 | useEffect(async() => { 7 | await LoadNFT(); 8 | }, []) 9 | 10 | const [parentID,setParentID] = useState(null); 11 | const [bagData,setBagData] = useState(null); 12 | const [items,setItems] = useState(null); 13 | 14 | useEffect(async() => { 15 | setTimeout(() => { 16 | if(bagData !== null) 17 | { 18 | setParentID(bagData.data.content.fields.items.fields.id.id); 19 | } 20 | }, 100); 21 | 22 | }, [bagData]) 23 | 24 | useEffect(async() => { 25 | setTimeout(async() => { 26 | if(parentID !== null) 27 | { 28 | const BagItem = await constant.client.call('suix_getDynamicFields',[parentID]); 29 | setItems(BagItem.data); 30 | } 31 | }, 100); 32 | 33 | }, [parentID]) 34 | 35 | 36 | async function LoadNFT(){ 37 | const bagData = await constant.client.call('sui_getObject', 38 | [constant.marketID, 39 | { 40 | "showType": true, 41 | "showOwner": true, 42 | "showPreviousTransaction": true, 43 | "showDisplay": true, 44 | "showContent": true, 45 | "showBcs": true, 46 | "showStorageRebate": true 47 | }]); 48 | setBagData(bagData); 49 | } 50 | 51 | return ( 52 |
53 | 54 |
55 | ); 56 | }; 57 | 58 | export default NFTsForSale; 59 | -------------------------------------------------------------------------------- /contract/Move.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contract" 3 | version = "0.0.1" 4 | 5 | # edition = "2024.beta" # To use the Move 2024 edition, currently in beta 6 | # license = "" # e.g., "MIT", "GPL", "Apache 2.0" 7 | # authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] 8 | 9 | [dependencies] 10 | Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/devnet" } 11 | 12 | # For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. 13 | # Revision can be a branch, a tag, and a commit hash. 14 | # MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" } 15 | 16 | # For local dependencies use `local = path`. Path is relative to the package root 17 | # Local = { local = "../path/to" } 18 | 19 | # To resolve a version conflict and force a specific version for dependency 20 | # override use `override = true` 21 | # Override = { local = "../conflicting/version", override = true } 22 | 23 | [addresses] 24 | contract = "0x0" 25 | sui = "0x2" 26 | 27 | # Named addresses will be accessible in Move as `@name`. They're also exported: 28 | # for example, `std = "0x1"` is exported by the Standard Library. 29 | # alice = "0xA11CE" 30 | 31 | [dev-dependencies] 32 | # The dev-dependencies section allows overriding dependencies for `--test` and 33 | # `--dev` modes. You can introduce test-only dependencies here. 34 | # Local = { local = "../path/to/dev-build" } 35 | 36 | [dev-addresses] 37 | # The dev-addresses section allows overwriting named addresses for the `--test` 38 | # and `--dev` modes. 39 | # alice = "0xB0B" 40 | 41 | -------------------------------------------------------------------------------- /front-end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nft-market", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@mysten/dapp-kit": "^0.5.0", 7 | "@mysten/sui.js": "^0.51.2", 8 | "@suiet/wallet-kit": "^0.2.20", 9 | "@tanstack/react-query": "^5.0.0", 10 | "@testing-library/jest-dom": "^5.16.1", 11 | "@testing-library/react": "^12.1.2", 12 | "@testing-library/user-event": "^13.5.0", 13 | "axios": "^0.25.0", 14 | "big-integer": "^1.6.52", 15 | "dom-to-image": "^2.6.0", 16 | "firebase": "^10.11.0", 17 | "moment": "^2.30.1", 18 | "openai": "^4.29.2", 19 | "or": "^0.2.0", 20 | "react": "^17.0.2", 21 | "react-bootstrap": "^2.10.2", 22 | "react-dom": "^17.0.2", 23 | "react-hot-toast": "^2.4.1", 24 | "react-icons": "^4.3.1", 25 | "react-modal": "^3.16.1", 26 | "react-router": "^6.2.1", 27 | "react-router-dom": "^6.2.1", 28 | "react-scripts": "5.0.0", 29 | "react-slick": "^0.28.1", 30 | "slick-carousel": "^1.8.1", 31 | "web-vitals": "^2.1.3" 32 | }, 33 | "scripts": { 34 | "start": "react-scripts start", 35 | "build": "react-scripts build", 36 | "test": "react-scripts test", 37 | "eject": "react-scripts eject" 38 | }, 39 | "eslintConfig": { 40 | "extends": [ 41 | "react-app", 42 | "react-app/jest" 43 | ] 44 | }, 45 | "browserslist": { 46 | "production": [ 47 | ">0.2%", 48 | "not dead", 49 | "not op_mini all" 50 | ], 51 | "development": [ 52 | "last 1 chrome version", 53 | "last 1 firefox version", 54 | "last 1 safari version" 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /front-end/src/constant/constant.js: -------------------------------------------------------------------------------- 1 | import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; 2 | import { initializeApp } from "firebase/app"; 3 | import { getStorage } from "firebase/storage"; 4 | 5 | export const packageObjectId = "0xd16182140b562ada0e47ce65ee753fb5b8e810f580cec8bf1dddad036b920423"; 6 | export const moduleName = "four_future_nft"; 7 | export const moduleMarketName = "marketplace"; 8 | export const OpenAIKey="";//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";//"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";//api key open AI 9 | export const defaultImgURL = "https://th.bing.com/th/id/OIP.eFAj7sVAyYiIDJU60PtUVwHaHa?rs=1&pid=ImgDetMain"; 10 | export const suiExploreLink = "https://suiscan.xyz/devnet/object/"; 11 | export const suiCoin = "0x2::sui::SUI"; 12 | export const marketID = "0xe65f96fe5f343936c3c6fb3ec2536c982d485a1e7533d7276b70a34ea6fa71f6"; 13 | export const bagID ="0xc61940851ca41571fbc72ac143d964410875d08ab707da992616a91c6b7f1c78"; 14 | export const typeArgNFT = packageObjectId+"::"+ moduleName+"::"+"FourFutureNFT"; 15 | export const rpcUrl = getFullnodeUrl('devnet'); 16 | export const client = new SuiClient({ url: rpcUrl }); 17 | export const bidMarketID = "0xad41455286f1bbd2b41a9d8ae1d75fe3b993300faf2d7f05e682c13d19b2cb58"; 18 | export const bidMarketBagID = "0xa2fb8149ae2072eff690395688604bdbc1d49ce46f8a368173e4229cb3b848f9"; 19 | 20 | // Your web app's Firebase configuration 21 | const firebaseConfig = { 22 | apiKey: "AIzaSyCSzOYVdOdgL0DZnDWqRydWRjTwoxAnghY", 23 | authDomain: "angular14-ab088.firebaseapp.com", 24 | projectId: "angular14-ab088", 25 | storageBucket: "angular14-ab088.appspot.com", 26 | messagingSenderId: "56427262623", 27 | appId: "1:56427262623:web:b6cd01412c0e014e20e8aa" 28 | }; 29 | 30 | // Initialize Firebase 31 | const app = initializeApp(firebaseConfig); 32 | export const storage = getStorage(app); -------------------------------------------------------------------------------- /front-end/src/pages/register/Register.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './register.css' 3 | import {Link} from 'react-router-dom' 4 | import Image from '../../assets/Image.png' 5 | 6 | const Register = () => { 7 | 8 | return ( 9 |
10 |
11 |

register

12 |

Upload Profile pic

13 |
14 | banner 15 |

browse media on your device

16 |
17 |
18 |
19 | 20 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 | 38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |
48 | ) 49 | }; 50 | 51 | export default Register; 52 | -------------------------------------------------------------------------------- /front-end/src/components/footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './footer.css' 3 | import nftlogo from '../../assets/logo.png' 4 | import { AiOutlineInstagram,AiOutlineTwitter, } from "react-icons/ai"; 5 | import { RiDiscordFill } from "react-icons/ri"; 6 | import { FaTelegramPlane } from "react-icons/fa"; 7 | const Footer = () => { 8 | return ( 9 |
10 |
11 |
12 |
13 | logo 14 |

4F TEAM

15 |
16 |
17 |

Get the lastes Updates

18 |
19 |
20 | 21 | 22 |
23 |
24 |
25 |

4F TEAM

26 |

Explore

27 |

How it Works

28 |

Counters

29 |

Contact Us

30 |
31 |
32 |

Support

33 |

Help center

34 |

Terms of service

35 |

Legal

36 |

Privacy policy

37 |
38 |
39 |
40 |
41 |

© {(new Date().getFullYear())} ForFuture, Inc. All Rights Reserved

42 |
43 |
44 | 45 | 46 | 47 | 48 |
49 | 50 |
51 |
52 | ) 53 | } 54 | 55 | export default Footer 56 | -------------------------------------------------------------------------------- /front-end/src/pages/profile/profile.css: -------------------------------------------------------------------------------- 1 | .profile{ 2 | padding: 0; 3 | /* padding-bottom: 6rem; */ 4 | } 5 | .profile-top{ 6 | position: relative; 7 | padding-bottom: 3.75rem; 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: center; 12 | } 13 | .profile-banner{ 14 | width: 100%; 15 | } 16 | .profile-banner img{ 17 | width: 100%; 18 | object-fit: cover; 19 | } 20 | .profile-pic{ 21 | display: flex; 22 | flex-direction: column; 23 | justify-content: center; 24 | align-items: center; 25 | width: 200px; 26 | margin-top: -100px; 27 | } 28 | .profile-pic img{ 29 | border: 6px solid var(--color-bg); 30 | border-radius: 50%; 31 | width: 70%; 32 | } 33 | .profile-pic h3{ 34 | font-family: var(--font-family); 35 | font-weight: 600; 36 | font-size: 28px; 37 | line-height: 42px; 38 | text-align: center; 39 | color: #FFFFFF; 40 | } 41 | .profile-bottom{ 42 | /* padding: 4rem 6rem; */ 43 | } 44 | .profile-bottom-input{ 45 | display: flex; 46 | justify-content: center; 47 | align-items: center; 48 | } 49 | .profile-bottom-input input{ 50 | background: #1B1A21; 51 | border-radius: 10px; 52 | border: none; 53 | padding: 7px 19px 7px 15px; 54 | font-family: var(--font-family); 55 | outline: none; 56 | color: whitesmoke; 57 | flex:0.3; 58 | display: flex; 59 | margin-right: 1rem; 60 | } 61 | .profile-bottom-input select{ 62 | background: #1B1A21; 63 | border-radius: 10px; 64 | border: none; 65 | padding: 7px 19px 7px 15px; 66 | font-family: var(--font-family); 67 | outline: none; 68 | color: whitesmoke; 69 | flex:0.1; 70 | display: flex; 71 | } 72 | 73 | @media screen and (max-width:1050px){ 74 | .profile-pic img{ 75 | width: 50%; 76 | } 77 | .profile-pic{ 78 | margin-top: -50px; 79 | } 80 | 81 | } 82 | @media screen and (max-width:550px){ 83 | .profile-pic h3{ 84 | font-weight: 600; 85 | font-size: 20px; 86 | line-height: 30px; 87 | } 88 | .profile.section__padding{ 89 | padding: 1rem 0px !important; 90 | } 91 | } 92 | @media screen and (max-width:500px){ 93 | .profile-bottom-input { 94 | display: none; 95 | } 96 | .profile-top{ 97 | padding-bottom: 1rem; 98 | } 99 | } -------------------------------------------------------------------------------- /front-end/src/pages/create/Create.jsx: -------------------------------------------------------------------------------- 1 | import './create.css' 2 | import Image from '../../assets/Image.png' 3 | const Create = () => { 4 | 5 | return ( 6 |
7 |
8 |

Create new Item

9 |

Upload File

10 |
11 |

JPG, PNG, GIF, SVG, WEBM, MP3, MP4. Max 100mb.

12 | banner 13 |

Drag and Drop File

14 |
15 |
16 | 17 |
18 | 19 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 | 31 |
32 |
33 | 34 |
35 | 36 | 41 |
42 |
43 |
44 | 45 | 53 |
54 |
55 | 56 | 57 |
58 | 59 |
60 |
61 |
62 | 63 | ) 64 | }; 65 | 66 | export default Create; 67 | -------------------------------------------------------------------------------- /front-end/src/pages/login/login.css: -------------------------------------------------------------------------------- 1 | .login{ 2 | display: flex; 3 | font-family: var(--font-family); 4 | color: white; 5 | justify-content: center; 6 | align-items: center; 7 | width: 100%; 8 | } 9 | .login-container { 10 | background: #2A2D3A; 11 | border-radius: 20px; 12 | padding: 2rem; 13 | min-width: 30%; 14 | } 15 | .login-container h1{ 16 | font-weight: 600; 17 | font-size: 48px; 18 | line-height: 42px; 19 | margin-bottom: 40px; 20 | text-align: center; 21 | text-transform: uppercase; 22 | margin-top: 20px; 23 | } 24 | 25 | .login-formGroup{ 26 | display: flex; 27 | flex-direction: column; 28 | margin-bottom: 30px; 29 | } 30 | .login-formGroup label{ 31 | font-weight: 600; 32 | font-size: 24px; 33 | line-height: 36px; 34 | margin-bottom: 20px; 35 | } 36 | .login-formGroup input{ 37 | background: #1B1A21; 38 | border-radius: 10px; 39 | padding: 1rem 1.5rem; 40 | outline: none; 41 | border: none; 42 | color: white; 43 | font-size: 16px; 44 | line-height: 26px; 45 | } 46 | 47 | .login-formGroup textarea{ 48 | background: #2D2E36; 49 | border-radius: 10px; 50 | padding: 1rem 1.5rem; 51 | outline: none; 52 | border: none; 53 | color: white; 54 | font-size: 16px; 55 | line-height: 26px; 56 | } 57 | .login-formGroup select{ 58 | background: #2D2E36; 59 | border-radius: 10px; 60 | padding: 1rem 1.5rem; 61 | outline: none; 62 | border: none; 63 | color: white; 64 | font-size: 16px; 65 | line-height: 26px; 66 | text-overflow: ellipsis; 67 | } 68 | .login-button{ 69 | display: flex; 70 | justify-content: space-between; 71 | align-items: center; 72 | } 73 | .login-writeButton{ 74 | /* float: right; */ 75 | background: var(--primary-btn); 76 | border: none; 77 | border-radius: 10px; 78 | padding: 12px 30px; 79 | color: white; 80 | font-weight: 600; 81 | font-size: 14px; 82 | line-height: 21px; 83 | } 84 | .login-reg-writeButton{ 85 | background-color: transparent; 86 | border: 1px solid var(--primary-color); 87 | border-radius: 10px; 88 | padding: 12px 30px; 89 | color: var(--primary-color); 90 | font-weight: 600; 91 | font-size: 14px; 92 | line-height: 21px; 93 | } 94 | @media screen and (max-width: 550px){ 95 | .login{ 96 | padding:2rem 1.5rem !important; 97 | 98 | } 99 | .login-container{ 100 | padding: 1.5rem 1rem; 101 | } 102 | .login-container h1{ 103 | /* display: none; */ 104 | font-size: 36px; 105 | margin-top: 0; 106 | } 107 | .login-formGroup label{ 108 | font-size: 20px; 109 | line-height: 30px; 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /front-end/src/pages/register/register.css: -------------------------------------------------------------------------------- 1 | .register{ 2 | display: flex; 3 | font-family: var(--font-family); 4 | color: white; 5 | justify-content: center; 6 | align-items: center; 7 | width: 100%; 8 | } 9 | .register-container { 10 | background: #2A2D3A; 11 | border-radius: 20px; 12 | padding: 2rem; 13 | min-width: 30%; 14 | } 15 | .register-container h1{ 16 | font-weight: 600; 17 | font-size: 48px; 18 | line-height: 42px; 19 | margin-bottom: 40px; 20 | text-align: center; 21 | text-transform: uppercase; 22 | margin-top: 20px; 23 | } 24 | 25 | .register-formGroup{ 26 | display: flex; 27 | flex-direction: column; 28 | margin-bottom: 30px; 29 | } 30 | .register-formGroup label{ 31 | font-weight: 600; 32 | font-size: 24px; 33 | line-height: 36px; 34 | margin-bottom: 15px; 35 | } 36 | .register-formGroup input{ 37 | background: #1B1A21; 38 | border-radius: 10px; 39 | padding: 1rem 1.5rem; 40 | outline: none; 41 | border: none; 42 | color: white; 43 | font-size: 16px; 44 | line-height: 26px; 45 | } 46 | 47 | .register-formGroup textarea{ 48 | background: #2D2E36; 49 | border-radius: 10px; 50 | padding: 1rem 1.5rem; 51 | outline: none; 52 | border: none; 53 | color: white; 54 | font-size: 16px; 55 | line-height: 26px; 56 | } 57 | .register-formGroup select{ 58 | background: #2D2E36; 59 | border-radius: 10px; 60 | padding: 1rem 1.5rem; 61 | outline: none; 62 | border: none; 63 | color: white; 64 | font-size: 16px; 65 | line-height: 26px; 66 | text-overflow: ellipsis; 67 | } 68 | .register-button{ 69 | display: flex; 70 | justify-content: space-between; 71 | align-items: center; 72 | } 73 | .register-writeButton{ 74 | /* float: right; */ 75 | background: var(--primary-btn); 76 | border: none; 77 | border-radius: 10px; 78 | padding: 12px 30px; 79 | color: white; 80 | font-weight: 600; 81 | font-size: 14px; 82 | line-height: 21px; 83 | } 84 | .reg-login-writeButton{ 85 | background-color: transparent; 86 | border: 1px solid var(--primary-color); 87 | border-radius: 10px; 88 | padding: 12px 30px; 89 | color: var(--primary-color); 90 | font-weight: 600; 91 | font-size: 14px; 92 | line-height: 21px; 93 | } 94 | @media screen and (max-width: 550px){ 95 | .register{ 96 | padding:2rem 1.5rem !important; 97 | 98 | } 99 | .register-container{ 100 | padding: 1.5rem 1rem; 101 | } 102 | .register-container h1{ 103 | /* display: none; */ 104 | font-size: 36px; 105 | margin-top: 0; 106 | } 107 | .register-formGroup label{ 108 | font-size: 20px; 109 | line-height: 30px; 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI-NFT-marketplace 2 | AI art NFT marketplace with SUI 3 | # Note for team member 4 | 1. Nghiên cứu zkLogin 5 | 2. smart contract run in Sui blockchain 6 | - mint NFT (build success) 7 | - mua bán đấu giá NFT 8 | 3. Chat GPT API tạo tác phẩm nghệ thuật đưa lên IPFS 9 | 4. Hoàn thiện Front-end 10 | # Run Front-end 11 | - cd front-end 12 | - npm install 13 | - npm start 14 | # Request faucet sui 15 | Explain 16 | curl --location --request POST 'https://faucet.devnet.sui.io/gas' \ 17 | --header 'Content-Type: application/json' \ 18 | --data-raw '{ 19 | "FixedAmountRequest": { 20 | "recipient": "0xf064667386cc04c513fffcbb89ad00c75935931e3d385c1580e8e7f771628123" 21 | } 22 | }' 23 | # Deploy contract 24 | - sui client publish --gas-budget 500000000 --skip-dependency-verification 25 | # Call contract function 26 | - sui mint nft 27 | sui client call --package 0x84cd2f10ccc37b0fc959c0df567d21ff24658674dd89de13ca6f06bf2b3b0265 --module four_future_nft --function mint_to_sender --args "meme01" "this is my first meme NFT" "https://media.istockphoto.com/id/538665020/vi/anh/meme-internet-t%E1%BA%A1i-sao-b%E1%BA%A1n-kh%C3%B4ng-h%C3%ACnh-minh-h%E1%BB%8Da-khu%C3%B4n-m%E1%BA%B7t-gi%E1%BA%ADn-d%E1%BB%AF-3d.jpg?s=1024x1024&w=is&k=20&c=qGypVnK46IEEqyLEgCC2ECQUubrInqSlj5m01eq8M7o=" --gas-budget 500000000 28 | 29 | - sui transfer nft 30 | sui client call --package 0x6d0789d49c77d321a9c07ee881eae608b1b710e9b14c691b8aa044118d4f0ad6 --module four_future_nft --function transfer --args 0xd3093e97245117a6dd586b8d8a56cef2ae64ce3906939803d0c1ed414f77d992 0xb021e9236da30c1564771893349d7fc4b83007e108636235bd3b89c893d313cb --gas-budget 500000000 31 | 32 | # Giai đoạn 2 33 | - Trang explore tạo tab phân ra 3 mục: 34 | + Tất cả NFT(trạng thái 1 và 2) 35 | + NFT for Vote(trạng thái 1) => mỗi lần kí thì NFT tăng 1 SUI 36 | + NFT for Sale (trạng thái 2) => khi người mua mua NFT đã được bán với giá được định sẵn thì số tiền (SUI) sẽ được gửi đến ví người bán và NFT sẽ được gửi đến ví người mua 37 | - Phân trang hiển thị NFT (Chỉnh sửa kích thước cố định cho ảnh trong card để tránh bị nhảy hàng), 1 trang hiển thị 10 NFT 38 | - market place contract gồm các tính năng List NFT, bán NFT, mua NFT, cho thuê NFT, vote NFT 39 | - Trang chi tiết item trong explore 40 | + Khi ở trạng thái vote thì kí contract tăng like cho NFT => mỗi lần kí thì NFT tăng 1 SUI 41 | + Khi ở trạng thái sale => khi người mua mua NFT đã được bán với giá được định sẵn thì số tiền (SUI) sẽ được gửi đến ví người bán và NFT sẽ được gửi đến ví người mua 42 | - Trang chi tiết my item: 43 | + List item lên sàn để vote hoặc bán thông qua việc thay đổi trạng thái NFT 44 | + Cập nhật mô tả ở trang my item và trang mint 45 | + tính năng transfer NFT sang ví khác 46 | + burn NFT 47 | # Dynamic Object Field 48 | Listing { 49 | ID 50 | IDNFT 51 | price 52 | state 53 | item => NFT 54 | owneraddress 55 | } 56 | 57 | ChangeState(address_Sender,listing,Newstate){ 58 | addressSender == owneraddress => event 59 | listing.state = Newstate 60 | } 61 | 62 | ChangePrice(listing){ 63 | listing.state != 1 => event 64 | listing.price += 1 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /front-end/src/components/bids/bids.css: -------------------------------------------------------------------------------- 1 | 2 | .bids-container{ 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | margin: auto; 8 | width: 100%; 9 | } 10 | 11 | .bids-container-text h1{ 12 | font-family: var(--font-family); 13 | font-weight: 600; 14 | font-size: 28px; 15 | line-height: 42px; 16 | color: #FFFFFF; 17 | margin-bottom: 1rem; 18 | } 19 | 20 | .bids-container-card{ 21 | margin: 0 -5px; 22 | } 23 | 24 | .bids-container-card:after { 25 | content: ""; 26 | display: table; 27 | clear: both; 28 | } 29 | 30 | .card-row-container{ 31 | display: flex; 32 | } 33 | 34 | .card-column{ 35 | float: left; 36 | width: 20%; 37 | } 38 | 39 | .bids-card{ 40 | background: #2A2D3A; 41 | border-radius: 20px; 42 | padding: 11px 12px 19px 11px; 43 | margin-inline: 10px; 44 | margin-bottom: 20px; 45 | } 46 | 47 | .bids-card img{ 48 | border-radius: 20px; 49 | width: 100%; 50 | } 51 | 52 | .bids-card-top p{ 53 | font-family: var(--font-family); 54 | font-weight: 600; 55 | font-size: 14px; 56 | line-height: 21px; 57 | color: #FFFFFF; 58 | margin-top: 15px; 59 | } 60 | 61 | .bids-card-bottom{ 62 | display: flex; 63 | justify-content: space-between; 64 | } 65 | 66 | .bids-card-bottom p{ 67 | font-family: var(--font-family); 68 | font-weight: 600; 69 | font-size: 12px; 70 | line-height: 18px; 71 | /* text-align: right; */ 72 | color: #FFFFFF; 73 | } 74 | 75 | .bids-card-bottom p:last-child{ 76 | font-weight: normal; 77 | } 78 | 79 | .bids-card-bottom span{ 80 | font-weight: normal; 81 | } 82 | 83 | .load-more{ 84 | display: flex; 85 | justify-content: center; 86 | align-items: center; 87 | margin-top: 2rem; 88 | } 89 | 90 | .load-more button{ 91 | background: transparent; 92 | border: 1px solid var(--primary-color); 93 | margin: 0 1rem; 94 | color: var(--primary-color); 95 | border-radius: 10px; 96 | padding: 10px 100px; 97 | font-family: Poppins; 98 | font-weight: 600; 99 | font-size: 14px; 100 | line-height: 21px; 101 | } 102 | 103 | .photo { 104 | height: 200px; 105 | width: 200px; 106 | } 107 | 108 | @media screen and (max-width: 1440px) { 109 | .card-column { 110 | width: 25%; 111 | } 112 | } 113 | 114 | 115 | @media screen and (max-width: 1200px) { 116 | .card-column { 117 | width: 33.33%; 118 | 119 | } 120 | } 121 | 122 | @media screen and (max-width: 900px) { 123 | .card-column { 124 | width: 50%; 125 | 126 | } 127 | } 128 | @media screen and (max-width: 550px) { 129 | .section__padding{ 130 | padding: 2rem 14px !important; 131 | } 132 | .bids-card{ 133 | margin-bottom: 10px; 134 | margin-inline: 5px; 135 | } 136 | .bids-card-top p{ 137 | font-size: 12px; 138 | line-height: 18px; 139 | margin-top: 5px; 140 | } 141 | .bids-card-bottom p{ 142 | font-size: 10px; 143 | line-height: 15px; 144 | } 145 | .bids-container{ 146 | width: 100%; 147 | } 148 | } 149 | 150 | -------------------------------------------------------------------------------- /front-end/src/components/ListItemOwner/ListItemOwner.css: -------------------------------------------------------------------------------- 1 | 2 | .bids-container{ 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | margin: auto; 8 | max-width: 100%; 9 | max-height: 100%; 10 | box-sizing: border-box; 11 | } 12 | .bids-container-text h1{ 13 | font-family: var(--font-family); 14 | font-weight: 600; 15 | font-size: 28px; 16 | line-height: 42px; 17 | color: #FFFFFF; 18 | margin-bottom: 1rem; 19 | } 20 | .bids-container-card{ 21 | margin: 0 -5px; 22 | } 23 | .bids-container-card:after { 24 | content: ""; 25 | display: table; 26 | clear: both; 27 | } 28 | 29 | .card-row-container{ 30 | display: flex; 31 | } 32 | 33 | .card-column{ 34 | float: left; 35 | width: 50%; 36 | max-width: max-content; 37 | max-height: max-content; 38 | } 39 | .bids-card{ 40 | width: 14rem; 41 | height: 16rem; 42 | background: #2A2D3A; 43 | border-radius: 20px; 44 | padding: 11px 12px 19px 11px; 45 | margin-inline: 10px; 46 | margin-bottom: 20px; 47 | } 48 | .bids-card img{ 49 | border-radius: 20px; 50 | width: 100%; 51 | } 52 | .bids-card-top p{ 53 | font-family: var(--font-family); 54 | font-weight: 600; 55 | font-size: 14px; 56 | line-height: 21px; 57 | color: #FFFFFF; 58 | margin-top: 15px; 59 | } 60 | .bids-card-bottom{ 61 | display: flex; 62 | justify-content: center; 63 | } 64 | .bids-card-bottom p{ 65 | font-family: var(--font-family); 66 | font-weight: 600; 67 | font-size: 12px; 68 | line-height: 18px; 69 | color: #FFFFFF; 70 | } 71 | .bids-card-bottom p:last-child{ 72 | font-weight: normal; 73 | 74 | } 75 | .bids-card-bottom span{ 76 | font-weight: normal; 77 | } 78 | .load-more{ 79 | display: flex; 80 | justify-content: center; 81 | align-items: center; 82 | margin-top: 2rem; 83 | } 84 | .load-more button{ 85 | background: transparent; 86 | border: 1px solid var(--primary-color); 87 | margin: 0 1rem; 88 | color: var(--primary-color); 89 | border-radius: 10px; 90 | padding: 10px 100px; 91 | font-family: Poppins; 92 | font-weight: 600; 93 | font-size: 14px; 94 | line-height: 21px; 95 | } 96 | 97 | .photo { 98 | height: 200px; 99 | width: 200px; 100 | } 101 | 102 | @media screen and (max-width: 1440px) { 103 | .card-column { 104 | width: 25%; 105 | } 106 | } 107 | 108 | 109 | @media screen and (max-width: 1200px) { 110 | .card-column { 111 | width: 33.33%; 112 | 113 | } 114 | } 115 | 116 | @media screen and (max-width: 900px) { 117 | .card-column { 118 | width: 50%; 119 | 120 | } 121 | } 122 | @media screen and (max-width: 550px) { 123 | .section__padding{ 124 | padding: 2rem 14px !important; 125 | } 126 | .bids-card{ 127 | margin-bottom: 10px; 128 | margin-inline: 5px; 129 | } 130 | .bids-card-top p{ 131 | font-size: 12px; 132 | line-height: 18px; 133 | margin-top: 5px; 134 | } 135 | .bids-card-bottom p{ 136 | font-size: 10px; 137 | line-height: 15px; 138 | } 139 | .bids-container{ 140 | width: 100%; 141 | } 142 | 143 | 144 | } 145 | 146 | -------------------------------------------------------------------------------- /front-end/src/components/TabComponents/AllNFTs/AllNFTs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Bids from '../../bids/Bids'; 3 | import bids1 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids1.png' 4 | import bids2 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids2.png' 5 | import bids3 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids3.png' 6 | import bids4 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids4.png' 7 | import bids5 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids5.png' 8 | import bids6 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids6.png' 9 | import bids7 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids7.png' 10 | import bids8 from 'F:/SUiProjectV3/AI-NFT-marketplace/front-end/src/assets/bids8.png' 11 | 12 | const data = [ 13 | {name:"Abstact Smoke Red",price:100,like:90,img:bids1,link:`/item/0`}, 14 | {name:"Mountain Landscape",price:50,like:100,img:bids2,link:`/item/1`}, 15 | {name:"White Line Grafiti",price:80,like:60,img:bids5,link:`/item/4`}, 16 | {name:"Abstract Triangle",price:90,like:5,img:bids6,link:`/item/5`}, 17 | {name:"Lake Landscape",price:53,like:52,img:bids7,link:`/item/6`}, 18 | {name:"Blue Red Art",price:51,like:51,img:bids8,link:`/item/7`}, 19 | {name:"Abstact Smoke Red",price:100,like:90,img:bids1,link:`/item/0`}, 20 | {name:"Mountain Landscape",price:50,like:100,img:bids2,link:`/item/1`}, 21 | {name:"Paint Color on Wall",price:60,like:102,img:bids3,link:`/item/2`}, 22 | {name:"Paint Color on Wall",price:60,like:102,img:bids3,link:`/item/2`}, 23 | {name:"Abstract Patern",price:70,like:75,img:bids4,link:`/item/3`}, 24 | {name:"White Line Grafiti",price:80,like:60,img:bids5,link:`/item/4`}, 25 | {name:"Abstract Triangle",price:90,like:5,img:bids6,link:`/item/5`}, 26 | {name:"Lake Landscape",price:53,like:52,img:bids7,link:`/item/6`}, 27 | {name:"Blue Red Art",price:51,like:51,img:bids8,link:`/item/7`}, 28 | {name:"White Line Grafiti",price:80,like:60,img:bids5,link:`/item/4`}, 29 | {name:"Abstract Triangle",price:90,like:5,img:bids6,link:`/item/5`}, 30 | {name:"Lake Landscape",price:53,like:52,img:bids7,link:`/item/6`}, 31 | {name:"Blue Red Art",price:51,like:51,img:bids8,link:`/item/7`}, 32 | {name:"Abstact Smoke Red",price:100,like:90,img:bids1,link:`/item/0`}, 33 | {name:"Mountain Landscape",price:50,like:100,img:bids2,link:`/item/1`}, 34 | {name:"Paint Color on Wall",price:60,like:102,img:bids3,link:`/item/2`}, 35 | {name:"Abstact Smoke Red",price:100,like:90,img:bids1,link:`/item/0`}, 36 | {name:"Mountain Landscape",price:50,like:100,img:bids2,link:`/item/1`}, 37 | {name:"Paint Color on Wall",price:60,like:102,img:bids3,link:`/item/2`}, 38 | {name:"Abstract Patern",price:70,like:75,img:bids4,link:`/item/3`}, 39 | {name:"White Line Grafiti",price:80,like:60,img:bids5,link:`/item/4`}, 40 | {name:"Abstract Triangle",price:90,like:5,img:bids6,link:`/item/5`}, 41 | {name:"Lake Landscape",price:53,like:52,img:bids7,link:`/item/6`}, 42 | {name:"Blue Red Art",price:51,like:51,img:bids8,link:`/item/7`}, 43 | ] 44 | 45 | const AllNFTs = () => { 46 | return ( 47 |
48 | {/* Filter data based on status (1 and 2) */} 49 | 50 |
51 | ); 52 | }; 53 | 54 | export default AllNFTs; 55 | -------------------------------------------------------------------------------- /front-end/src/components/navbar/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React,{ useState} from 'react' 2 | import './navbar.css' 3 | import { RiMenu3Line, RiCloseLine } from 'react-icons/ri'; 4 | import logo from '../../assets/logo.png' 5 | import { Link } from "react-router-dom"; 6 | import {ConnectButton} from '@suiet/wallet-kit'; 7 | const Menu = () => ( 8 | <> 9 |

Explore

10 |

Mint

11 |

My Items

12 | 13 | ) 14 | 15 | const Navbar = () => { 16 | const [toggleMenu,setToggleMenu] = useState(false) 17 | const [user,setUser] = useState(false) 18 | 19 | const handleLogout = () => { 20 | setUser(false); 21 | } 22 | const handleLogin = () => { 23 | setUser(true); 24 | } 25 | 26 | return ( 27 |
28 |
29 |
30 | logo 31 | 32 |

4F TEAM

33 | 34 |
35 |
36 | 37 | 38 | {user &&

Logout

} 39 | 40 |
41 |
42 |
43 | {user ? ( 44 | <> 45 | 46 | 47 | 48 | 49 | 50 | ): ( 51 | <> 52 | Connect Wallet 53 | {/* 54 | 55 | 56 | 57 | 58 | */} 59 | 60 | )} 61 | 62 | 63 | 64 |
65 |
66 | {toggleMenu ? 67 | setToggleMenu(false)} /> 68 | : setToggleMenu(true)} />} 69 | {toggleMenu && ( 70 |
71 |
72 | 73 |
74 |
75 | {user ? ( 76 | <> 77 | 78 | 79 | 80 | 81 | 82 | ): ( 83 | <> 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | )} 92 | 93 |
94 |
95 | )} 96 |
97 |
98 | ) 99 | } 100 | 101 | export default Navbar 102 | -------------------------------------------------------------------------------- /front-end/src/components/navbar/navbar.css: -------------------------------------------------------------------------------- 1 | .navbar{ 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | padding: 2rem 6rem; 6 | border-bottom: 1px solid rgba(165, 165, 165, 0.1); 7 | } 8 | .navbar-links{ 9 | flex: 1; 10 | display: flex; 11 | justify-content: flex-start; 12 | align-items: center; 13 | } 14 | .navbar-links_logo{ 15 | margin-right: 2rem; 16 | display: flex; 17 | align-items: center; 18 | color: white; 19 | 20 | } 21 | .navbar-links_logo h1{ 22 | font-family: var(--font-family); 23 | font-weight: bold; 24 | font-size: 18px; 25 | line-height: 17px; 26 | } 27 | .navbar-links_logo img{ 28 | margin-right: 5px; 29 | } 30 | .navbar-links_container{ 31 | display: flex; 32 | flex-direction: row; 33 | position: relative; 34 | align-items: center; 35 | } 36 | .navbar-links_container input { 37 | background: #1B1A21; 38 | border-radius: 10px; 39 | border: none; 40 | padding: 7px 19px 7px 15px; 41 | font-family: var(--font-family); 42 | outline: none; 43 | color: whitesmoke; 44 | } 45 | 46 | .navbar-sign{ 47 | display: flex; 48 | justify-content: flex-end; 49 | align-items: center; 50 | } 51 | .navbar-links_container p, 52 | .navbar-sign p, 53 | .navbar-menu_container p{ 54 | color: #fff; 55 | font-family: var(--font-family); 56 | font-weight: 500; 57 | font-size: 18px; 58 | line-height: 25px; 59 | text-transform: capitalize; 60 | margin: 0 1rem; 61 | cursor: pointer; 62 | } 63 | .navbar-sign .primary-btn, 64 | .navbar-menu_container-links-sign .primary-btn 65 | { 66 | background: var(--primary-btn); 67 | border-radius: 10px; 68 | } 69 | .navbar-sign .secondary-btn, 70 | .navbar-menu_container-links-sign .secondary-btn 71 | { 72 | background: transparent; 73 | border: 1px solid var(--primary-color); 74 | margin: 0 1rem; 75 | color: var(--primary-color); 76 | border-radius: 10px; 77 | } 78 | 79 | .navbar-sign button, 80 | .navbar-menu_container button{ 81 | color: #fff; 82 | padding: 0.5rem 1rem; 83 | font-family: var(--font-family); 84 | font-weight: 500; 85 | border: none; 86 | font-size: 16px; 87 | } 88 | .navbar-menu{ 89 | margin-left: 1rem; 90 | display: none; 91 | position: relative; 92 | } 93 | .navbar-menu svg{ 94 | cursor: pointer; 95 | } 96 | .navbar-menu_container{ 97 | display: flex; 98 | justify-content: flex-end; 99 | align-items: flex-end; 100 | flex-direction: column; 101 | text-align: end; 102 | background: var(--color-footer); 103 | padding: 2rem; 104 | position: absolute; 105 | top: 40px; 106 | right: 0; 107 | margin-top: 1rem; 108 | width: 100%; 109 | min-width: 210px; 110 | border-radius: 5px; 111 | box-shadow: 0 0 5 rgba(0,0,0,0.2); 112 | z-index: 99; 113 | } 114 | .navbar-menu_container p { 115 | margin: 1rem 0; 116 | } 117 | .navbar-menu_container-links-sign{ 118 | display: none; 119 | } 120 | @media screen and (max-width:1050px) { 121 | .navbar-links_container{ 122 | display: none; 123 | } 124 | .navbar-menu{ 125 | display: flex; 126 | } 127 | 128 | } 129 | 130 | @media screen and (max-width:700px) { 131 | .navbar{ 132 | padding: 2rem 4rem; 133 | } 134 | } 135 | @media screen and (max-width:550px) { 136 | .navbar{ 137 | padding: 2rem; 138 | } 139 | 140 | .navbar-sign{ 141 | display: none; 142 | } 143 | .navbar-menu_container{ 144 | top: 20px; 145 | } 146 | .navbar-menu_container-links-sign{ 147 | display: block; 148 | } 149 | 150 | .navbar-menu_container-links-sign .secondary-btn{ 151 | margin: 1rem 0; 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /front-end/src/pages/create/create.css: -------------------------------------------------------------------------------- 1 | .create{ 2 | display: flex; 3 | font-family: var(--font-family); 4 | color: white; 5 | justify-content: center; 6 | align-items: center; 7 | width: 100%; 8 | } 9 | .create-container h1{ 10 | font-weight: 600; 11 | font-size: 28px; 12 | line-height: 42px; 13 | margin-bottom: 40px; 14 | } 15 | .create-container .upload-file { 16 | font-weight: 600; 17 | font-size: 28px; 18 | line-height: 42px; 19 | margin-bottom: 20px; 20 | } 21 | .upload-img-show{ 22 | background: #2D2E36; 23 | /* White */ 24 | padding: 30px 40px; 25 | border: 1px dashed #FFFFFF; 26 | box-sizing: border-box; 27 | border-radius: 10px; 28 | display: flex; 29 | flex-direction: column; 30 | align-items: center; 31 | justify-content: center; 32 | margin-bottom: 50px; 33 | } 34 | .upload-img-show h3{ 35 | font-weight: 600; 36 | font-size: 20px; 37 | line-height: 30px; 38 | margin-bottom: 20px; 39 | } 40 | .upload-img-show img{ 41 | margin-bottom: 20px; 42 | } 43 | .upload-img-show p{ 44 | font-weight: 600; 45 | font-size: 14px; 46 | line-height: 21px; 47 | } 48 | .upload-img-show span{ 49 | font-weight: normal; 50 | } 51 | .formGroup{ 52 | display: flex; 53 | flex-direction: column; 54 | margin-bottom: 50px; 55 | } 56 | .formGroup label{ 57 | font-weight: 600; 58 | font-size: 24px; 59 | line-height: 36px; 60 | margin-bottom: 20px; 61 | } 62 | .formGroup input{ 63 | background: #2D2E36; 64 | border-radius: 10px; 65 | padding: 1rem 1.5rem; 66 | outline: none; 67 | border: none; 68 | color: white; 69 | font-size: 16px; 70 | line-height: 26px; 71 | width: 100%; 72 | } 73 | 74 | .formGroup textarea{ 75 | background: #2D2E36; 76 | border-radius: 10px; 77 | padding: 1rem 1.5rem; 78 | outline: none; 79 | border: none; 80 | color: white; 81 | font-size: 16px; 82 | line-height: 26px; 83 | } 84 | .formGroup select{ 85 | background: #2D2E36; 86 | border-radius: 10px; 87 | padding: 1rem 1.5rem; 88 | outline: none; 89 | border: none; 90 | color: white; 91 | font-size: 16px; 92 | line-height: 26px; 93 | text-overflow: ellipsis; 94 | } 95 | .writeForm button{ 96 | float: right; 97 | background: var(--primary-btn); 98 | border: none; 99 | border-radius: 10px; 100 | padding: 12px 30px; 101 | color: white; 102 | font-weight: 600; 103 | font-size: 14px; 104 | line-height: 21px; 105 | } 106 | .twoForm{ 107 | display: flex; 108 | justify-content: space-between; 109 | } 110 | .twoForm input { 111 | width: 100%; 112 | margin-right: 15px; 113 | } 114 | .custom-file-input { 115 | color: transparent; 116 | } 117 | .custom-file-input::-webkit-file-upload-button { 118 | visibility: hidden; 119 | } 120 | .custom-file-input::before { 121 | content: 'Select file'; 122 | color: black; 123 | width: auto; 124 | display: inline-flex; 125 | background: -webkit-linear-gradient(top, #f9f9f9, #e3e3e3); 126 | border: 1px solid #999; 127 | border-radius: 3px; 128 | padding: 5px 8px; 129 | outline: none; 130 | white-space: nowrap; 131 | -webkit-user-select: none; 132 | cursor: pointer; 133 | text-shadow: 1px 1px #fff; 134 | font-weight: 700; 135 | font-size: 10pt; 136 | } 137 | .custom-file-input:hover::before { 138 | border-color: black; 139 | } 140 | .custom-file-input:active { 141 | outline: 0; 142 | } 143 | .custom-file-input:active::before { 144 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9); 145 | } 146 | @media screen and (max-width: 550px){ 147 | .create{ 148 | padding:2rem 1.5rem !important; 149 | 150 | } 151 | .create-container h1{ 152 | display: none; 153 | margin-bottom: 20px; 154 | } 155 | } -------------------------------------------------------------------------------- /front-end/src/test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AI Image Generator 7 | 46 | 47 | 48 | 49 |

AI Image Generator

50 |

The generator will take around one minute to generate nine images. 51 |
The images will be of a high quality (1024x1024) pixels

API Link 52 |
53 | 54 |
55 | 58 | 59 |
60 |
61 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /front-end/src/components/bids/Bids.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState,useEffect } from 'react' 2 | import './bids.css' 3 | import { AiFillHeart, AiOutlineHeart } from "react-icons/ai"; 4 | import Pagination from '../Pagination/Pagination'; 5 | import * as constant from '../../constant/constant'; 6 | 7 | const Bids = ({ title,data,parentID,status }) => { 8 | 9 | const pageNumberLimit = 100; 10 | const [passengersData, setData] = useState([]); 11 | const [loading, setLoading] = useState(true); 12 | const [currentPage, setCurrentPage] = useState(1); 13 | const [maxPageLimit, setMaxPageLimit] = useState(10); 14 | const [minPageLimit, setMinPageLimit] = useState(0); 15 | const [totalPage, setTotalPage] = useState(pageNumberLimit); 16 | 17 | useEffect(async()=>{ 18 | setTimeout(async() => { 19 | setLoading(true); 20 | console.log(data); 21 | const listResData = []; 22 | if(data != null && data.length>0){ 23 | const startIndex = (currentPage - 1) * maxPageLimit; 24 | const endIndex = startIndex + maxPageLimit; 25 | const totalPages = Math.ceil(data.length / maxPageLimit); 26 | setTotalPage(totalPages); 27 | for(const d of data.slice(startIndex, endIndex)){ 28 | if(status == 1) 29 | { 30 | const listDetailNFT = await constant.client.call('sui_getObject', [d.name.value,{"showContent": true}]); 31 | const price = await constant.client.call('suix_getDynamicFieldObject',[parentID,d.name]); 32 | listResData.push({ 33 | d:listDetailNFT.data.content.fields, 34 | p:price.data.content.fields.value.fields 35 | }); 36 | } 37 | else 38 | { 39 | if(d!=null && d.data.content.fields.to_sell != null) 40 | { 41 | console.log(d); 42 | const listDetailNFT = d.data.content.fields.to_sell.fields; ; 43 | listResData.push({ 44 | d:listDetailNFT, 45 | p:{ 46 | ask: d.data.content.fields.set_change, 47 | owner: d.data.content.fields.owner, 48 | autionID: d.data.objectId 49 | }, 50 | q:d.data.content.fields.bid_data 51 | }); 52 | } 53 | 54 | } 55 | }; 56 | setData(listResData); 57 | setLoading(false); 58 | } 59 | }, 100); 60 | 61 | },[currentPage,data,parentID]); 62 | 63 | const onPageChange= (pageNumber)=>{ 64 | setCurrentPage(pageNumber); 65 | } 66 | const onPrevClick = ()=>{ 67 | if((currentPage-1) % pageNumberLimit === 0){ 68 | setMaxPageLimit(maxPageLimit - pageNumberLimit); 69 | setMinPageLimit(minPageLimit - pageNumberLimit); 70 | } 71 | setCurrentPage(prev=> prev-1); 72 | } 73 | 74 | const onNextClick = ()=>{ 75 | if(currentPage+1 > maxPageLimit){ 76 | setMaxPageLimit(maxPageLimit + pageNumberLimit); 77 | setMinPageLimit(minPageLimit + pageNumberLimit); 78 | } 79 | setCurrentPage(prev=>prev+1); 80 | } 81 | 82 | const paginationAttributes = { 83 | currentPage, 84 | maxPageLimit, 85 | minPageLimit, 86 | totalPages: totalPage, 87 | data: passengersData, 88 | title: title, 89 | type:status, 90 | }; 91 | 92 | return ( 93 | 94 | {!loading ? 99 | :

Loading...

100 | } 101 |
102 | ) 103 | } 104 | 105 | export default Bids 106 | -------------------------------------------------------------------------------- /front-end/src/components/footer/footer.css: -------------------------------------------------------------------------------- 1 | .footer{ 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | background: var(--color-footer); 7 | border-top: 1px solid rgba(165, 165, 165, 0.1); 8 | padding-bottom: 2rem; 9 | } 10 | 11 | .footer-btn p{ 12 | box-sizing: border-box; 13 | font-family: var(--font-family); 14 | font-size: 18px; 15 | line-height: 21px; 16 | color: #FFFFFF; 17 | } 18 | .footer-links{ 19 | display: flex; 20 | justify-content: space-around; 21 | align-items: flex-start; 22 | flex-wrap: wrap; 23 | flex-direction: row; 24 | 25 | width: 100%; 26 | text-align: left; 27 | } 28 | .footer-links div{ 29 | width: 250px; 30 | margin: 1rem; 31 | } 32 | .footer-links_logo { 33 | display: flex; 34 | flex-direction: column; 35 | align-items: center; 36 | justify-content: center; 37 | } 38 | .footer-links_logo div{ 39 | display: flex; 40 | align-items: center; 41 | position: relative; 42 | } 43 | .footer-links_logo div h3{ 44 | font-family: var(--font-family); 45 | font-weight: 600; 46 | font-size: 16px; 47 | line-height: 24px; 48 | color: #FFFFFF; 49 | } 50 | .footer-links_logo img { 51 | width: 32px; 52 | height: 32px; 53 | margin-right: 4px; 54 | } 55 | .footer-links_logo p{ 56 | font-family: var(--font-family); 57 | font-weight: bold; 58 | font-size: 18px; 59 | line-height: 17px; 60 | color: #FFFFFF; 61 | } 62 | .footer-links_logo input { 63 | background: #1B1A21; 64 | border-radius: 10px; 65 | border: none; 66 | padding: 13px; 67 | color: #fff; 68 | font-family: var(--font-family); 69 | font-weight: 500; 70 | font-size: 14px; 71 | line-height: 105.7%; 72 | outline: none; 73 | } 74 | .footer-links_logo button{ 75 | background: var(--primary-btn); 76 | border: none; 77 | border-radius: 10px; 78 | font-family: var(--font-family); 79 | font-weight: 600; 80 | font-size: 14px; 81 | line-height: 21px; 82 | color: #FFFFFF; 83 | padding: 12px 18px; 84 | white-space: nowrap; 85 | position: absolute; 86 | right: -2rem; 87 | } 88 | 89 | .footer-links_div{ 90 | display: flex; 91 | justify-content: flex-start; 92 | flex-direction: column; 93 | } 94 | .footer-links_div h4{ 95 | font-family: var(--font-family); 96 | font-weight: 600; 97 | font-size: 20px; 98 | line-height: 30px; 99 | color: #FFFFFF; 100 | margin-bottom: 1rem; 101 | } 102 | .footer-links_div p{ 103 | font-family: var(--font-family); 104 | font-weight: normal; 105 | font-size: 16px; 106 | line-height: 26px; 107 | color: #FFFFFF; 108 | margin: 0.5rem 0; 109 | cursor: pointer; 110 | } 111 | .footer-copyright{ 112 | margin-top: 2rem; 113 | text-align: center; 114 | width: 100%; 115 | display: flex; 116 | justify-content: space-around; 117 | border-top: 1px solid rgba(165, 165, 165, 0.1); 118 | padding-top: 2rem; 119 | } 120 | .footer-copyright p{ 121 | font-family: var(--font-family); 122 | font-weight: 600; 123 | font-size: 16px; 124 | line-height: 24px; 125 | color: #FFFFFF; 126 | } 127 | .footer-icon{ 128 | margin-inline: 10px; 129 | } 130 | @media screen and (max-width: 850px) { 131 | .footer-heading h1 { 132 | font-size: 44px; 133 | line-height: 50px; 134 | } 135 | } 136 | 137 | @media screen and (max-width: 550px) { 138 | .footer-heading h1 { 139 | font-size: 34px; 140 | line-height: 42px; 141 | } 142 | 143 | .footer-links div { 144 | margin: 1rem 0; 145 | } 146 | 147 | .footer-btn p { 148 | font-size: 14px; 149 | line-height: 20px; 150 | } 151 | } 152 | 153 | @media screen and (max-width: 400px) { 154 | .footer-heading h1 { 155 | font-size: 27px; 156 | line-height: 38px; 157 | } 158 | } -------------------------------------------------------------------------------- /front-end/src/components/ListItemOwner/ListItemOwner.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect,useState } from 'react' 2 | import './ListItemOwner.css' 3 | import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; 4 | import { useWallet } from '@suiet/wallet-kit'; 5 | import Pagination from '../Pagination/Pagination'; 6 | 7 | 8 | const ListItemOwner = () => { 9 | const wallet = useWallet(); 10 | const rpcUrl = getFullnodeUrl('devnet'); 11 | const client = new SuiClient({ url: rpcUrl }); 12 | var listObjectID = []; 13 | const [dataObjectID,setDataObjectID] = useState(null); 14 | const [data, setData] = useState(null); 15 | 16 | const pageNumberLimit = 100; 17 | const [passengersData, setpassengersData] = useState([]); 18 | const [loading, setLoading] = useState(true); 19 | const [currentPage, setCurrentPage] = useState(1); 20 | const [maxPageLimit, setMaxPageLimit] = useState(6); 21 | const [minPageLimit, setMinPageLimit] = useState(0); 22 | const [totalPage, setTotalPage] = useState(pageNumberLimit); 23 | 24 | useEffect(() => { 25 | if (!wallet.connected) return; 26 | // console.log('connected wallet name: ', wallet.name) 27 | // console.log('account address: ', wallet.account?.address) 28 | // console.log('account publicKey: ', wallet.account?.publicKey) 29 | getNFT(); 30 | }, [wallet.connected]) 31 | 32 | useEffect(async()=>{ 33 | setLoading(true); 34 | const listNFT = []; 35 | if(dataObjectID!= null) 36 | { 37 | const totalPages = Math.ceil(dataObjectID.length / maxPageLimit); 38 | setTotalPage(totalPages); 39 | const startIndex = (currentPage - 1) * maxPageLimit; 40 | const endIndex = startIndex + maxPageLimit; 41 | const currentItems = listNFT;// data.slice(startIndex, endIndex); 42 | setpassengersData(currentItems); 43 | setLoading(false); 44 | for(const id of dataObjectID.slice(startIndex, endIndex)){ 45 | const infoObject = await client.call('sui_getObject', [id,{"showContent": true}]); 46 | if(infoObject.data.content.fields.name!= null) 47 | { 48 | listNFT.push(infoObject.data.content.fields) 49 | } 50 | }; 51 | //console.log(listNFT); 52 | setData(listNFT); 53 | } 54 | },[currentPage,dataObjectID]); 55 | 56 | const onPageChange= (pageNumber)=>{ 57 | setCurrentPage(pageNumber); 58 | } 59 | const onPrevClick = ()=>{ 60 | if((currentPage-1) % pageNumberLimit === 0){ 61 | setMaxPageLimit(maxPageLimit - pageNumberLimit); 62 | setMinPageLimit(minPageLimit - pageNumberLimit); 63 | } 64 | setCurrentPage(prev=> prev-1); 65 | } 66 | 67 | const onNextClick = ()=>{ 68 | if(currentPage+1 > maxPageLimit){ 69 | setMaxPageLimit(maxPageLimit + pageNumberLimit); 70 | setMinPageLimit(minPageLimit + pageNumberLimit); 71 | } 72 | setCurrentPage(prev=>prev+1); 73 | } 74 | 75 | const paginationAttributes = { 76 | currentPage, 77 | maxPageLimit, 78 | minPageLimit, 79 | totalPages: totalPage, 80 | data: passengersData, 81 | title: "List of My NFTs", 82 | type:3, 83 | }; 84 | 85 | 86 | 87 | async function getNFT() { 88 | const committeeInfo = await client.call('suix_getOwnedObjects', [wallet.account?.address]); 89 | committeeInfo?.data.forEach(id => { 90 | listObjectID.push(id.data.objectId); 91 | }); 92 | console.log(listObjectID); 93 | setDataObjectID(listObjectID); 94 | } 95 | 96 | 97 | return ( 98 |
99 | {!loading ? 104 | :

Loading...

105 | } 106 |
107 | ) 108 | } 109 | 110 | export default ListItemOwner 111 | -------------------------------------------------------------------------------- /front-end/src/App.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background: var(--color-bg); 3 | scroll-behavior: smooth; 4 | } 5 | a{ 6 | text-decoration: none; 7 | color: inherit; 8 | } 9 | 10 | .gradient__bg{ 11 | 12 | /* ff 3.6+ */ 13 | background:-moz-radial-gradient(circle at 0% 29%, rgba(0, 40, 83, 1) 0%, rgba(4, 12, 24, 1) 100%); 14 | 15 | /* safari 5.1+,chrome 10+ */ 16 | background:-webkit-radial-gradient(circle at 0% 29%, rgba(0, 40, 83, 1) 0%, rgba(4, 12, 24, 1) 100%); 17 | 18 | /* opera 11.10+ */ 19 | background:-o-radial-gradient(circle at 0% 29%, rgba(0, 40, 83, 1) 0%, rgba(4, 12, 24, 1) 100%); 20 | 21 | /* ie 10+ */ 22 | background:-ms-radial-gradient(circle at 0% 29%, rgba(0, 40, 83, 1) 0%, rgba(4, 12, 24, 1) 100%); 23 | 24 | /* global 92%+ browsers support */ 25 | background:radial-gradient(circle at 0% 29%, rgba(0, 40, 83, 1) 0%, rgba(4, 12, 24, 1) 100%); 26 | 27 | 28 | } 29 | .gradient__text{ 30 | background: var(--gradient-text); 31 | background-clip: text; 32 | -webkit-background-clip: text; 33 | -webkit-text-fill-color: transparent; 34 | } 35 | .section__padding{ 36 | padding: 4rem 6rem; 37 | } 38 | .section__margin{ 39 | margin: 4rem 6rem; 40 | } 41 | .scale-up-center { 42 | -webkit-animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both; 43 | animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both; 44 | } 45 | 46 | button{ 47 | cursor: pointer; 48 | } 49 | 50 | @-webkit-keyframes scale-up-center { 51 | 0% { 52 | -webkit-transform: scale(0.5); 53 | transform: scale(0.5); 54 | } 55 | 100% { 56 | -webkit-transform: scale(1); 57 | transform: scale(1); 58 | } 59 | } 60 | @keyframes scale-up-center { 61 | 0% { 62 | -webkit-transform: scale(0.5); 63 | transform: scale(0.5); 64 | } 65 | 100% { 66 | -webkit-transform: scale(1); 67 | transform: scale(1); 68 | } 69 | } 70 | 71 | 72 | @media screen and (max-width: 700px){ 73 | .section__padding{ 74 | padding:4rem 6rem; 75 | } 76 | .section__margin{ 77 | margin:4rem; 78 | } 79 | } 80 | @media screen and (max-width: 550px){ 81 | .section__padding{ 82 | padding: 4rem 2rem !important; 83 | } 84 | .section__margin{ 85 | margin:4rem 2rem; 86 | } 87 | } 88 | 89 | .loader-container { 90 | width: 100%; 91 | height: 100vh; 92 | position: fixed; 93 | background: rgba(0, 0, 0, 0.834) url("assets/loading.gif") center no-repeat; 94 | z-index: 1; 95 | } 96 | 97 | 98 | { 99 | box-sizing: border-box; 100 | padding: 0; 101 | margin: 0; 102 | } 103 | // Style App.js wrapper 104 | .App { 105 | width: 100vw; 106 | height: 100vh; 107 | display: flex; 108 | align-items: center; 109 | justify-content: center; 110 | overflow: hidden; 111 | } 112 | 113 | /* Tab Container */ 114 | .Tabs { 115 | width: 100%; 116 | height: auto; 117 | min-height: 400px; 118 | background: transparent; 119 | margin: 3.5rem auto 1.5rem; 120 | padding: 2rem 1rem; 121 | color: #E8F0F2; 122 | border-radius: 2rem; 123 | @media (max-width: 769px) { 124 | padding: 2rem 0; 125 | } 126 | 127 | } 128 | 129 | /* Tab Navigation */ 130 | ul.nav { 131 | width: 60%; 132 | margin: 0 auto 2rem; 133 | padding: 0.1rem; 134 | display: flex; 135 | align-items: center; 136 | justify-content: space-between; 137 | border: 1px solid #fc0fc0; 138 | border-radius: 2rem; 139 | @media (max-width: 768px) { 140 | width: 90%; 141 | } 142 | } 143 | ul.nav li { 144 | width: 50%; 145 | padding: 1rem; 146 | list-style: none; 147 | text-align: center; 148 | cursor: pointer; 149 | transition: all 0.7s; 150 | border-bottom-left-radius: 2rem; 151 | border-top-left-radius: 2rem; 152 | } 153 | ul.nav li:nth-child(2) { 154 | border-radius: 0; 155 | border-bottom-right-radius: 2rem; 156 | border-top-right-radius: 2rem; 157 | } 158 | ul.nav li:hover { 159 | background: #ffb6c1; 160 | } 161 | ul.nav li.active { 162 | background: #fc0fc0; 163 | } 164 | 165 | /* First and Second Tab Styles */ 166 | .AllNFTTab p, 167 | .NFTVoteTab p { 168 | font-size: 2rem; 169 | text-align: center; 170 | } 171 | .NFTSaleTab p { 172 | font-size: 2rem; 173 | text-align: center; 174 | } 175 | -------------------------------------------------------------------------------- /front-end/src/components/nftMint/nftMint.css: -------------------------------------------------------------------------------- 1 | 2 | .bids-container{ 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | margin: auto; 8 | width: 100%; 9 | } 10 | .bids-container-text h1{ 11 | font-family: var(--font-family); 12 | font-weight: 600; 13 | font-size: 28px; 14 | line-height: 42px; 15 | color: #FFFFFF; 16 | margin-bottom: 1rem; 17 | text-align: center; 18 | } 19 | 20 | .bids-container-text h6{ 21 | font-family: var(--font-family); 22 | font-weight: 500; 23 | font-size: 16px; 24 | line-height: 1px; 25 | color: #FFFFFF; 26 | text-align: center; 27 | } 28 | 29 | .bids-container-text a h6 hover{ 30 | font-family: var(--font-family); 31 | font-weight: 500; 32 | font-size: 16px; 33 | line-height: 1px; 34 | color: #696969; 35 | text-align: center; 36 | background-color: yellow; 37 | } 38 | 39 | .bids-container-card{ 40 | margin: 0 -5px; 41 | text-align: center; 42 | } 43 | .bids-container-card:after { 44 | content: ""; 45 | display: table; 46 | clear: both; 47 | } 48 | 49 | .card-row-container{ 50 | display: flex; 51 | align-items: center; 52 | justify-content: center; 53 | } 54 | 55 | .card-column{ 56 | width: 20%; 57 | } 58 | .bids-card{ 59 | background: #2A2D3A; 60 | border-radius: 20px; 61 | padding: 11px 12px 19px 11px; 62 | margin-inline: 10px; 63 | margin-bottom: 20px; 64 | text-align: center; 65 | } 66 | .bids-card img{ 67 | border-radius: 20px; 68 | width: 100%; 69 | } 70 | .bids-card-top p{ 71 | font-family: var(--font-family); 72 | font-weight: 600; 73 | font-size: 14px; 74 | line-height: 21px; 75 | color: #FFFFFF; 76 | margin-top: 15px; 77 | } 78 | .bids-card-bottom{ 79 | display: flex; 80 | justify-content: space-between; 81 | } 82 | .bids-card-bottom p{ 83 | font-family: var(--font-family); 84 | font-weight: 600; 85 | font-size: 12px; 86 | line-height: 18px; 87 | /* text-align: right; */ 88 | color: #FFFFFF; 89 | } 90 | .bids-card-bottom p:last-child{ 91 | font-weight: normal; 92 | 93 | } 94 | .bids-card-bottom span{ 95 | font-weight: normal; 96 | } 97 | .load-more{ 98 | display: flex; 99 | justify-content: center; 100 | align-items: center; 101 | margin-top: 2rem; 102 | } 103 | .load-more button{ 104 | background: transparent; 105 | border: 1px solid var(--primary-color); 106 | margin: 0 1rem; 107 | color: var(--primary-color); 108 | border-radius: 10px; 109 | padding: 10px 100px; 110 | font-family: Poppins; 111 | font-weight: 600; 112 | font-size: 14px; 113 | line-height: 21px; 114 | } 115 | 116 | .load-more button:disabled, 117 | button[disabled]{ 118 | background: transparent; 119 | border: 1px solid grey; 120 | margin: 0 1rem; 121 | color: grey; 122 | border-radius: 10px; 123 | padding: 10px 100px; 124 | font-family: Poppins; 125 | font-weight: 600; 126 | font-size: 14px; 127 | line-height: 21px; 128 | } 129 | 130 | .load-more button:hover{ 131 | background: var(--secondary-color); 132 | border: 1px solid var(--secondary-color); 133 | margin: 0 1rem; 134 | color: white; 135 | border-radius: 10px; 136 | padding: 10px 100px; 137 | font-family: Poppins; 138 | font-weight: 600; 139 | font-size: 14px; 140 | line-height: 21px; 141 | } 142 | 143 | .photo { 144 | height: 200px; 145 | width: 200px; 146 | } 147 | 148 | @media screen and (max-width: 1440px) { 149 | .card-column { 150 | width: 25%; 151 | } 152 | } 153 | 154 | 155 | @media screen and (max-width: 1200px) { 156 | .card-column { 157 | width: 33.33%; 158 | 159 | } 160 | } 161 | 162 | @media screen and (max-width: 900px) { 163 | .card-column { 164 | width: 50%; 165 | 166 | } 167 | } 168 | @media screen and (max-width: 550px) { 169 | .section__padding{ 170 | padding: 2rem 14px !important; 171 | } 172 | .bids-card{ 173 | margin-bottom: 10px; 174 | margin-inline: 5px; 175 | } 176 | .bids-card-top p{ 177 | font-size: 12px; 178 | line-height: 18px; 179 | margin-top: 5px; 180 | } 181 | .bids-card-bottom p{ 182 | font-size: 10px; 183 | line-height: 15px; 184 | } 185 | .bids-container{ 186 | width: 100%; 187 | } 188 | 189 | 190 | } 191 | 192 | -------------------------------------------------------------------------------- /front-end/src/pages/item/item.css: -------------------------------------------------------------------------------- 1 | .item{ 2 | display: flex; 3 | padding: 0 6rem; 4 | font-family: var(--font-family); 5 | } 6 | .item-image{ 7 | flex: 1; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | border-right: 1px solid rgba(165, 165, 165, 0.1); 12 | 13 | } 14 | .item-image img { 15 | width: 100%; 16 | height: 100%; 17 | border-radius: 70px; 18 | padding: 50px; 19 | } 20 | .item-content{ 21 | flex:1; 22 | display: flex; 23 | justify-content: flex-start; 24 | align-items: flex-start; 25 | flex-direction: column; 26 | margin: 5rem; 27 | position: relative; 28 | } 29 | 30 | .item-content-title h1{ 31 | font-family: var(--font-family); 32 | font-weight: 600; 33 | font-size: 28px; 34 | line-height: 42px; 35 | color: #FFFFFF; 36 | } 37 | .item-content-title p{ 38 | font-family: var(--font-family); 39 | font-weight: normal; 40 | font-size: 14px; 41 | line-height: 21px; 42 | color: #FFFFFF; 43 | } 44 | .item-content-title span{ 45 | font-weight: 600; 46 | } 47 | .item-content-creator{ 48 | margin-top: 30px; 49 | } 50 | .item-content-creator p{ 51 | font-size: 12px; 52 | line-height: 18px; 53 | color: #FFFFFF; 54 | } 55 | .item-content-creator div{ 56 | display: flex; 57 | align-items: center; 58 | margin-top: 10px; 59 | } 60 | .item-content-creator div:last-child p{ 61 | font-weight: 600; 62 | font-size: 14px; 63 | line-height: 21px; 64 | color: #FFFFFF; 65 | } 66 | .item-content-creator img { 67 | border-radius: 50%; 68 | margin-right: 10px; 69 | width: 50px; 70 | height: 50px; 71 | } 72 | .item-content-detail{ 73 | margin-top: 30px; 74 | margin-bottom: 30px; 75 | border-top: 1px solid rgba(165, 165, 165, 0.1); 76 | padding-top: 20px; 77 | } 78 | .item-content-detail p{ 79 | font-size: 16px; 80 | line-height: 26px; 81 | color: #FFFFFF; 82 | width: 500px; 83 | } 84 | .item-content-buy .primary-btn{ 85 | background: var(--primary-btn); 86 | border-radius: 10px; 87 | border: none; 88 | padding: 0.75rem 3rem; 89 | font-size: 14px; 90 | line-height: 21px; 91 | font-weight: 600; 92 | color: #fff; 93 | margin-right: 20px; 94 | } 95 | .item-content-buy .secondary-btn{ 96 | background: transparent; 97 | border-radius: 10px; 98 | border: 1px solid var(--primary-color); 99 | padding: 0.70rem 3rem; 100 | font-size: 14px; 101 | line-height: 21px; 102 | font-weight: 600; 103 | color: var(--primary-color); 104 | } 105 | .item-content-action{ 106 | display: flex; 107 | position: absolute; 108 | right: 0; 109 | } 110 | .item-content-action p{ 111 | cursor: pointer; 112 | font-size: 18px; 113 | color: white; 114 | background: var(--primary-btn); 115 | margin-inline: 10px; 116 | border-radius: 5px; 117 | padding: 5px 5px 0px 5px; 118 | } 119 | @media screen and (max-width: 1050px) { 120 | .item{ 121 | flex-direction: column; 122 | } 123 | .item-content{ 124 | margin: 0 0 3rem; 125 | } 126 | .item-image{ 127 | border-right: unset; 128 | } 129 | .item-content-detail p{ 130 | width: 100%; 131 | } 132 | } 133 | 134 | @media screen and (max-width: 650px) { 135 | .item-content h1{ 136 | font-size: 28px; 137 | line-height: 42px; 138 | } 139 | .item-content p{ 140 | font-size: 16px; 141 | line-height: 24px; 142 | } 143 | .item-content__people{ 144 | flex-direction: column; 145 | } 146 | .item-content__people p{ 147 | margin: 0; 148 | } 149 | .item-content__input input, 150 | .item-content__input button{ 151 | font-size: 16px; 152 | line-height: 24px; 153 | } 154 | .item-content-buy .primary-btn{ 155 | padding: 0.75rem 20px; 156 | 157 | } 158 | .item-content-buy .secondary-btn{ 159 | padding: 0.75rem 33px; 160 | } 161 | } 162 | @media screen and (max-width: 490px){ 163 | .item-content h1{ 164 | font-size: 28px; 165 | line-height: 42px; 166 | } 167 | .item-content p{ 168 | font-size: 14px; 169 | line-height: 26px; 170 | } 171 | .item-content__input input, 172 | .item-content__input button{ 173 | font-size: 12px; 174 | line-height: 16px; 175 | } 176 | .item{ 177 | padding-inline:1rem !important ; 178 | padding-top: 1rem !important; 179 | } 180 | .item-image img{ 181 | padding: 0; 182 | border-radius: 20px; 183 | margin-bottom: 25px; 184 | } 185 | .item-content-buy .primary-btn{ 186 | margin-right: 10px; 187 | 188 | } 189 | .item-content-action{ 190 | top: 15%; 191 | } 192 | .item-content-action p{ 193 | margin-inline: 5px; 194 | 195 | } 196 | 197 | } -------------------------------------------------------------------------------- /front-end/src/pages/bidItem/BidItem.css: -------------------------------------------------------------------------------- 1 | .item{ 2 | display: flex; 3 | padding: 0 6rem; 4 | font-family: var(--font-family); 5 | } 6 | .item-image{ 7 | flex: 1; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | border-right: 1px solid rgba(165, 165, 165, 0.1); 12 | 13 | } 14 | .item-image img { 15 | width: 100%; 16 | height: 100%; 17 | border-radius: 70px; 18 | padding: 50px; 19 | } 20 | .item-content{ 21 | flex:1; 22 | display: flex; 23 | justify-content: flex-start; 24 | align-items: flex-start; 25 | flex-direction: column; 26 | margin: 5rem; 27 | position: relative; 28 | } 29 | 30 | .item-content-title h1{ 31 | font-family: var(--font-family); 32 | font-weight: 600; 33 | font-size: 28px; 34 | line-height: 42px; 35 | color: #FFFFFF; 36 | } 37 | .item-content-title p{ 38 | font-family: var(--font-family); 39 | font-weight: normal; 40 | font-size: 14px; 41 | line-height: 21px; 42 | color: #FFFFFF; 43 | } 44 | .item-content-title span{ 45 | font-weight: 600; 46 | } 47 | .item-content-creator{ 48 | margin-top: 30px; 49 | } 50 | .item-content-creator p{ 51 | font-size: 12px; 52 | line-height: 18px; 53 | color: #FFFFFF; 54 | } 55 | .item-content-creator div{ 56 | display: flex; 57 | align-items: center; 58 | margin-top: 10px; 59 | } 60 | .item-content-creator div:last-child p{ 61 | font-weight: 600; 62 | font-size: 14px; 63 | line-height: 21px; 64 | color: #FFFFFF; 65 | } 66 | .item-content-creator img { 67 | border-radius: 50%; 68 | margin-right: 10px; 69 | width: 50px; 70 | height: 50px; 71 | } 72 | .item-content-detail{ 73 | margin-top: 30px; 74 | margin-bottom: 30px; 75 | border-top: 1px solid rgba(165, 165, 165, 0.1); 76 | padding-top: 20px; 77 | } 78 | .item-content-detail p{ 79 | font-size: 16px; 80 | line-height: 26px; 81 | color: #FFFFFF; 82 | width: 500px; 83 | } 84 | .item-content-buy .primary-btn{ 85 | background: var(--primary-btn); 86 | border-radius: 10px; 87 | border: none; 88 | padding: 0.75rem 3rem; 89 | font-size: 14px; 90 | line-height: 21px; 91 | font-weight: 600; 92 | color: #fff; 93 | margin-right: 20px; 94 | } 95 | .item-content-buy .secondary-btn{ 96 | background: transparent; 97 | border-radius: 10px; 98 | border: 1px solid var(--primary-color); 99 | padding: 0.70rem 3rem; 100 | font-size: 14px; 101 | line-height: 21px; 102 | font-weight: 600; 103 | color: var(--primary-color); 104 | } 105 | .item-content-action{ 106 | display: flex; 107 | position: absolute; 108 | right: 0; 109 | } 110 | .item-content-action p{ 111 | cursor: pointer; 112 | font-size: 18px; 113 | color: white; 114 | background: var(--primary-btn); 115 | margin-inline: 10px; 116 | border-radius: 5px; 117 | padding: 5px 5px 0px 5px; 118 | } 119 | @media screen and (max-width: 1050px) { 120 | .item{ 121 | flex-direction: column; 122 | } 123 | .item-content{ 124 | margin: 0 0 3rem; 125 | } 126 | .item-image{ 127 | border-right: unset; 128 | } 129 | .item-content-detail p{ 130 | width: 100%; 131 | } 132 | } 133 | 134 | @media screen and (max-width: 650px) { 135 | .item-content h1{ 136 | font-size: 28px; 137 | line-height: 42px; 138 | } 139 | .item-content p{ 140 | font-size: 16px; 141 | line-height: 24px; 142 | } 143 | .item-content__people{ 144 | flex-direction: column; 145 | } 146 | .item-content__people p{ 147 | margin: 0; 148 | } 149 | .item-content__input input, 150 | .item-content__input button{ 151 | font-size: 16px; 152 | line-height: 24px; 153 | } 154 | .item-content-buy .primary-btn{ 155 | padding: 0.75rem 20px; 156 | 157 | } 158 | .item-content-buy .secondary-btn{ 159 | padding: 0.75rem 33px; 160 | } 161 | } 162 | @media screen and (max-width: 490px){ 163 | .item-content h1{ 164 | font-size: 28px; 165 | line-height: 42px; 166 | } 167 | .item-content p{ 168 | font-size: 14px; 169 | line-height: 26px; 170 | } 171 | .item-content__input input, 172 | .item-content__input button{ 173 | font-size: 12px; 174 | line-height: 16px; 175 | } 176 | .item{ 177 | padding-inline:1rem !important ; 178 | padding-top: 1rem !important; 179 | } 180 | .item-image img{ 181 | padding: 0; 182 | border-radius: 20px; 183 | margin-bottom: 25px; 184 | } 185 | .item-content-buy .primary-btn{ 186 | margin-right: 10px; 187 | 188 | } 189 | .item-content-action{ 190 | top: 15%; 191 | } 192 | .item-content-action p{ 193 | margin-inline: 5px; 194 | 195 | } 196 | 197 | } -------------------------------------------------------------------------------- /contract/sources/four_future_nft.move: -------------------------------------------------------------------------------- 1 | module contract::four_future_nft { 2 | use std::string; 3 | use sui::url::{Self, Url}; 4 | use sui::object::{Self, ID, UID}; 5 | use sui::tx_context::{Self, TxContext}; 6 | use sui::event; 7 | use sui::transfer; 8 | 9 | // Struct represent the NFT item 10 | struct FourFutureNFT has key, store { 11 | id: UID, 12 | /// Name for the token 13 | name: string::String, 14 | /// Description of the token 15 | description: string::String, 16 | /// URL for the token 17 | url: Url, 18 | } 19 | 20 | struct NFTMinted has copy, drop { 21 | // The Object ID of the NFT 22 | object_id: ID, 23 | // The creator of the NFT 24 | creator: address, 25 | // The name of the NFT 26 | name: string::String, 27 | // The description of the NFT 28 | description: string::String, 29 | // The url of the NFT 30 | url: Url, 31 | } 32 | 33 | struct NFTTransfered has copy, drop { 34 | // The Object ID of the NFT 35 | object_id: ID, 36 | // The sender of the NFT 37 | sender_nft: address, 38 | // The receive of the NFT 39 | receive: address, 40 | } 41 | 42 | struct NFTDescriptionUpdated has copy, drop { 43 | // The Object ID of the NFT 44 | object_id: ID, 45 | // The creator update description 46 | creator_updated: address, 47 | // The new description updated 48 | new_description_updated: string::String, 49 | } 50 | 51 | struct NFTBurned has copy, drop { 52 | // The creator update description 53 | creator_burned: address, 54 | } 55 | 56 | // ===== Public view functions ===== 57 | 58 | /// Get the NFT's `ID` 59 | public fun get_id(nft: &FourFutureNFT): &UID { 60 | &nft.id 61 | } 62 | 63 | /// Get the NFT's `name` 64 | public fun get_name(nft: &FourFutureNFT): &string::String { 65 | &nft.name 66 | } 67 | 68 | /// Get the NFT's `description` 69 | public fun get_description(nft: &FourFutureNFT): &string::String { 70 | &nft.description 71 | } 72 | 73 | /// Get the NFT's `url` 74 | public fun get_url(nft: &FourFutureNFT): &Url { 75 | &nft.url 76 | } 77 | 78 | // ===== Entrypoints ===== 79 | 80 | #[allow(lint(self_transfer))] 81 | public fun mint_to_sender( 82 | name: vector, 83 | description: vector, 84 | url: vector, 85 | ctx: &mut TxContext, 86 | ) { 87 | 88 | let sender = tx_context::sender(ctx); 89 | let nft = FourFutureNFT { 90 | id: object::new(ctx), 91 | name: string::utf8(name), 92 | description: string::utf8(description), 93 | url: url::new_unsafe_from_bytes(url), 94 | }; 95 | 96 | event::emit(NFTMinted { 97 | object_id: object::id(&nft), 98 | creator: sender, 99 | name: nft.name, 100 | description: nft.description, 101 | url: nft.url, 102 | }); 103 | 104 | transfer::public_transfer(nft, sender); 105 | } 106 | 107 | /// Transfer `nft` to `recipient` 108 | public fun transfer( 109 | nft: FourFutureNFT, 110 | recipient: address, 111 | ctx: &mut TxContext 112 | ) { 113 | 114 | let sender = tx_context::sender(ctx); 115 | 116 | event::emit(NFTTransfered { 117 | object_id: object::id(&nft), 118 | sender_nft: sender, 119 | receive: recipient, 120 | }); 121 | 122 | transfer::public_transfer(nft, recipient) 123 | } 124 | 125 | /// Update the `description` of `nft` to `new_description` 126 | public fun update_description( 127 | nft: &mut FourFutureNFT, 128 | new_description: vector, 129 | ctx: &mut TxContext 130 | ) { 131 | 132 | let sender = tx_context::sender(ctx); 133 | 134 | event::emit(NFTDescriptionUpdated { 135 | object_id: object::id(nft), 136 | creator_updated: sender, 137 | new_description_updated: string::utf8(new_description) 138 | }); 139 | 140 | nft.description = string::utf8(new_description) 141 | } 142 | 143 | /// Permanently delete `nft` 144 | public fun burn( 145 | nft_burn: FourFutureNFT, 146 | ctx: &mut TxContext 147 | ) { 148 | 149 | let sender = tx_context::sender(ctx); 150 | 151 | event::emit(NFTBurned { 152 | creator_burned: sender 153 | }); 154 | 155 | let FourFutureNFT { id, name: _, description: _, url: _ } = nft_burn; 156 | object::delete(id) 157 | } 158 | 159 | } -------------------------------------------------------------------------------- /front-end/src/pages/DetailItemOwner/DetailItemOwner.css: -------------------------------------------------------------------------------- 1 | .item{ 2 | display: flex; 3 | padding: 0 6rem; 4 | font-family: var(--font-family); 5 | } 6 | .item-image{ 7 | flex: 1; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | border-right: 1px solid rgba(165, 165, 165, 0.1); 12 | 13 | } 14 | .item-image img { 15 | width: 100%; 16 | height: 100%; 17 | border-radius: 70px; 18 | padding: 50px; 19 | } 20 | .item-content{ 21 | flex:1; 22 | display: flex; 23 | justify-content: flex-start; 24 | align-items: flex-start; 25 | flex-direction: column; 26 | margin: 5rem; 27 | position: relative; 28 | } 29 | 30 | .item-content-title h1{ 31 | font-family: var(--font-family); 32 | font-weight: 600; 33 | font-size: 28px; 34 | line-height: 42px; 35 | color: #FFFFFF; 36 | } 37 | .item-content-title p{ 38 | font-family: var(--font-family); 39 | font-weight: normal; 40 | font-size: 14px; 41 | line-height: 21px; 42 | color: #FFFFFF; 43 | } 44 | .item-content-title span{ 45 | font-weight: 600; 46 | } 47 | .item-content-creator{ 48 | margin-top: 30px; 49 | } 50 | .item-content-creator p{ 51 | font-size: 12px; 52 | line-height: 18px; 53 | color: #FFFFFF; 54 | } 55 | .item-content-creator div{ 56 | display: flex; 57 | align-items: center; 58 | margin-top: 10px; 59 | } 60 | .item-content-creator div:last-child p{ 61 | font-weight: 600; 62 | font-size: 14px; 63 | line-height: 21px; 64 | color: #FFFFFF; 65 | } 66 | .item-content-creator img { 67 | border-radius: 50%; 68 | margin-right: 10px; 69 | width: 50px; 70 | height: 50px; 71 | } 72 | .item-content-detail{ 73 | margin-top: 30px; 74 | margin-bottom: 30px; 75 | border-top: 1px solid rgba(165, 165, 165, 0.1); 76 | padding-top: 20px; 77 | } 78 | .item-content-detail p{ 79 | font-size: 16px; 80 | line-height: 26px; 81 | color: #FFFFFF; 82 | width: 500px; 83 | } 84 | .item-content-buy .primary-btn{ 85 | background: var(--primary-btn); 86 | border-radius: 10px; 87 | border: none; 88 | padding: 0.70rem 3rem; 89 | font-size: 14px; 90 | line-height: 21px; 91 | font-weight: 600; 92 | color: #fff; 93 | margin: 30px; 94 | } 95 | 96 | .item-content-buy .secondary-btn{ 97 | background: transparent; 98 | border-radius: 10px; 99 | border: 1px solid var(--primary-color); 100 | padding: 0.70rem 3rem; 101 | font-size: 14px; 102 | line-height: 21px; 103 | font-weight: 600; 104 | color: var(--primary-color); 105 | margin: 30px; 106 | } 107 | 108 | .modal-content{ 109 | display: flex; 110 | justify-content: space-between; 111 | } 112 | 113 | .item-content-action{ 114 | display: flex; 115 | position: absolute; 116 | right: 0; 117 | } 118 | .item-content-action p{ 119 | cursor: pointer; 120 | font-size: 18px; 121 | color: white; 122 | background: var(--primary-btn); 123 | margin-inline: 10px; 124 | border-radius: 5px; 125 | padding: 5px 5px 0px 5px; 126 | } 127 | @media screen and (max-width: 1050px) { 128 | .item{ 129 | flex-direction: column; 130 | } 131 | .item-content{ 132 | margin: 0 0 3rem; 133 | } 134 | .item-image{ 135 | border-right: unset; 136 | } 137 | .item-content-detail p{ 138 | width: 100%; 139 | } 140 | } 141 | 142 | @media screen and (max-width: 650px) { 143 | .item-content h1{ 144 | font-size: 28px; 145 | line-height: 42px; 146 | } 147 | .item-content p{ 148 | font-size: 16px; 149 | line-height: 24px; 150 | } 151 | .item-content__people{ 152 | flex-direction: column; 153 | } 154 | .item-content__people p{ 155 | margin: 0; 156 | } 157 | .item-content__input input, 158 | .item-content__input button{ 159 | font-size: 16px; 160 | line-height: 24px; 161 | } 162 | .item-content-buy .primary-btn{ 163 | padding: 0.75rem 33px; 164 | } 165 | .item-content-buy .secondary-btn{ 166 | padding: 0.75rem 33px; 167 | } 168 | } 169 | @media screen and (max-width: 490px){ 170 | .item-content h1{ 171 | font-size: 28px; 172 | line-height: 42px; 173 | } 174 | .item-content p{ 175 | font-size: 14px; 176 | line-height: 26px; 177 | } 178 | .item-content__input input, 179 | .item-content__input button{ 180 | font-size: 12px; 181 | line-height: 16px; 182 | } 183 | .item{ 184 | padding-inline:1rem !important ; 185 | padding-top: 1rem !important; 186 | } 187 | .item-image img{ 188 | padding: 0; 189 | border-radius: 20px; 190 | margin-bottom: 25px; 191 | } 192 | .item-content-buy .primary-btn{ 193 | margin-right: 10px; 194 | } 195 | .item-content-action{ 196 | top: 15%; 197 | } 198 | .item-content-action p{ 199 | margin-inline: 5px; 200 | 201 | } 202 | 203 | } -------------------------------------------------------------------------------- /front-end/src/components/header/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './header.css' 3 | import "slick-carousel/slick/slick.css"; 4 | import "slick-carousel/slick/slick-theme.css"; 5 | import Slider from "react-slick"; 6 | import seller1 from '../../assets/seller1.jpg' 7 | import seller2 from '../../assets/seller2.png' 8 | import seller3 from '../../assets/seller3.png' 9 | import seller4 from '../../assets/seller4.png' 10 | import seller5 from '../../assets/seller5.png' 11 | import seller6 from '../../assets/seller6.jpg' 12 | import verify from '../../assets/verify.png' 13 | import coin from '../../assets/coin.png' 14 | import { Link } from 'react-router-dom'; 15 | const Header = () => { 16 | var settings = { 17 | dots: false, 18 | infinite: false, 19 | speed: 500, 20 | slidesToShow: 5, 21 | slidesToScroll: 1, 22 | initialSlide: 0, 23 | swipeToSlide:true, 24 | responsive: [ 25 | { 26 | breakpoint: 1160, 27 | settings: { 28 | slidesToShow: 4, 29 | slidesToScroll: 1, 30 | swipeToSlide:true, 31 | } 32 | }, 33 | { 34 | breakpoint: 950, 35 | settings: { 36 | slidesToShow: 3, 37 | slidesToScroll: 1, 38 | swipeToSlide:true, 39 | } 40 | }, 41 | { 42 | breakpoint: 750, 43 | settings: { 44 | slidesToShow: 2, 45 | slidesToScroll: 1, 46 | initialSlide: 2, 47 | } 48 | }, 49 | { 50 | breakpoint: 550, 51 | settings: { 52 | slidesToShow: 3, 53 | slidesToScroll: 1 54 | } 55 | }, 56 | { 57 | breakpoint: 470, 58 | settings: { 59 | slidesToShow: 2, 60 | slidesToScroll: 1, 61 | } 62 | }, 63 | { 64 | breakpoint: 400, 65 | settings: { 66 | slidesToShow: 2, 67 | slidesToScroll: 1, 68 | variableWidth: true, 69 | } 70 | } 71 | ] 72 | }; 73 | return ( 74 |
75 |
76 |
77 |

Create your AI NFTs and make a vote

78 | 79 |
80 |
81 |
82 |

Top Sellers

83 | 84 |
85 |

1

86 |
87 | 88 | 89 |
90 | 91 |

James Bond

92 | 93 |

5.250 SUI

94 |
95 |
96 |

2

97 |
98 | 99 | 100 |
101 | 102 |

Rian Leon

103 | 104 |

4.932 SUI

105 |
106 |
107 |

3

108 |
109 | 110 | 111 |
112 | 113 |

Lady Young

114 | 115 |

4.620 SUI

116 |
117 |
118 |

4

119 |
120 | 121 | 122 |
123 | 124 |

Black Glass

125 | 126 |

4.125 SUI

127 |
128 |
129 |

5

130 |
131 | 132 | 133 |
134 | 135 |

Budhiman

136 | 137 |

3.921 SUI

138 |
139 |
140 |

6

141 |
142 | 143 | 144 |
145 | 146 |

Alex

147 | 148 |

3.548 SUI

149 |
150 |
151 |
152 |
153 | ) 154 | } 155 | 156 | export default Header 157 | -------------------------------------------------------------------------------- /front-end/src/components/Pagination/Pagination.css: -------------------------------------------------------------------------------- 1 | 2 | .bids-container{ 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | margin: auto; 8 | width: 100%; 9 | } 10 | .bids-container-text h1{ 11 | font-family: var(--font-family); 12 | font-weight: 600; 13 | font-size: 28px; 14 | line-height: 42px; 15 | color: #FFFFFF; 16 | margin-bottom: 1rem; 17 | } 18 | .bids-container-card{ 19 | margin: 0 -5px; 20 | } 21 | .bids-container-card:after { 22 | content: ""; 23 | display: table; 24 | clear: both; 25 | } 26 | 27 | .card-row-container{ 28 | display: flex; 29 | } 30 | 31 | .card-column{ 32 | float: left; 33 | width: 20%; 34 | } 35 | .bids-card{ 36 | background: #2A2D3A; 37 | border-radius: 20px; 38 | padding: 11px 12px 19px 11px; 39 | margin-inline: 10px; 40 | margin-bottom: 20px; 41 | } 42 | .bids-card img{ 43 | border-radius: 20px; 44 | width: 100%; 45 | } 46 | .bids-card-top p{ 47 | font-family: var(--font-family); 48 | font-weight: 600; 49 | font-size: 14px; 50 | line-height: 21px; 51 | color: #FFFFFF; 52 | margin-top: 15px; 53 | } 54 | .bids-card-bottom{ 55 | display: flex; 56 | justify-content: space-between; 57 | } 58 | .bids-card-bottom p{ 59 | font-family: var(--font-family); 60 | font-weight: 600; 61 | font-size: 12px; 62 | line-height: 18px; 63 | /* text-align: right; */ 64 | color: #FFFFFF; 65 | } 66 | .bids-card-bottom p:last-child{ 67 | font-weight: normal; 68 | 69 | } 70 | .bids-card-bottom span{ 71 | font-weight: normal; 72 | } 73 | .load-more{ 74 | display: flex; 75 | justify-content: center; 76 | align-items: center; 77 | margin-top: 2rem; 78 | } 79 | 80 | .photo { 81 | height: 200px; 82 | width: 200px; 83 | } 84 | 85 | @media screen and (max-width: 1440px) { 86 | .card-column { 87 | width: 25%; 88 | } 89 | } 90 | 91 | 92 | @media screen and (max-width: 1200px) { 93 | .card-column { 94 | width: 33.33%; 95 | 96 | } 97 | } 98 | 99 | @media screen and (max-width: 900px) { 100 | .card-column { 101 | width: 50%; 102 | 103 | } 104 | } 105 | @media screen and (max-width: 550px) { 106 | .section__padding{ 107 | padding: 2rem 14px !important; 108 | } 109 | .bids-card{ 110 | margin-bottom: 10px; 111 | margin-inline: 5px; 112 | } 113 | .bids-card-top p{ 114 | font-size: 12px; 115 | line-height: 18px; 116 | margin-top: 5px; 117 | } 118 | .bids-card-bottom p{ 119 | font-size: 10px; 120 | line-height: 15px; 121 | } 122 | .bids-container{ 123 | width: 100%; 124 | } 125 | } 126 | 127 | .pageNumbers { 128 | display: flex; 129 | justify-content: center; 130 | align-items: center; 131 | height: 50px; 132 | } 133 | 134 | .pageNumbers li{ 135 | display:inline; 136 | } 137 | 138 | .pageNumbers ul{ 139 | overflow-x:hidden; 140 | white-space:nowrap; 141 | height: 1em; 142 | width: 100%; 143 | } 144 | 145 | 146 | .page-link { 147 | position: relative; 148 | display: inline-flex; 149 | border: 1px solid #dee2e6; 150 | background-color: #ffffff; 151 | padding: 10px 15px; 152 | color: #0d6efd; 153 | font-size: 16px; 154 | font-weight: 500; 155 | text-decoration: none; 156 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, 157 | border-color 0.15s ease-in-out; 158 | cursor: pointer; 159 | } 160 | 161 | .pageNumbers:first-child { 162 | border-top-left-radius: 5px; 163 | border-bottom-left-radius: 5px; 164 | } 165 | 166 | .pageNumbers:last-child { 167 | border-top-right-radius: 5px; 168 | border-bottom-right-radius: 5px; 169 | } 170 | 171 | button{ 172 | background-color: #fc0fc0; 173 | color: white; 174 | border-radius: 50%; 175 | } 176 | 177 | .active{ 178 | background:#fc0fc0; 179 | color: white; 180 | } 181 | 182 | .pageNumbers:mid { 183 | border-top-right-radius: 5px; 184 | border-bottom-right-radius: 5px; 185 | background:#FFC0CB; 186 | } 187 | 188 | .pageNumbers:not(:first-child) { 189 | margin-left: -1px; 190 | } 191 | 192 | .pageNumbers:hover, 193 | .pageNumbers:focus { 194 | color: #0a58ca; 195 | } 196 | 197 | .pageNumbers:focus { 198 | z-index: 3; 199 | } 200 | 201 | .pageNumbers.active { 202 | z-index: 2; 203 | color: #ffffff; 204 | border-color: #0d6efd; 205 | background-color: #0d6efd; 206 | } 207 | 208 | .pageNumbers.disabled { 209 | color: #6c757d; 210 | pointer-events: none; 211 | } 212 | 213 | .prev-button { 214 | background-color: #fc0fc0; 215 | color: white; 216 | border: none; 217 | height: 40px; 218 | width: 100px; 219 | font-weight: bold; 220 | font-size: 15px; 221 | border-radius: 20px; 222 | cursor: pointer; 223 | margin-right: 10px; 224 | transition: background-color 0.15s; 225 | } 226 | 227 | .prev-button:hover { 228 | background-image: linear-gradient(to right, rgba(222, 176, 216, 0), rgb(232, 131, 229)); 229 | } 230 | 231 | .next-button { 232 | background-color: #fc0fc0; 233 | color: white; 234 | border: none; 235 | height: 40px; 236 | width: 100px; 237 | font-weight: bold; 238 | font-size: 15px; 239 | border-radius: 20px; 240 | cursor: pointer; 241 | margin-right: 10px; 242 | transition: background-color 0.15s; 243 | } 244 | 245 | .next-button:hover { 246 | background-image: linear-gradient(to right, rgba(222, 176, 216, 0), rgb(232, 131, 229)); 247 | } 248 | -------------------------------------------------------------------------------- /front-end/src/components/header/header.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | margin: auto; 7 | } 8 | .header-content div{ 9 | background: var(--primary-btn); 10 | width: 100%; 11 | height: 300px; 12 | border-radius: 25px; 13 | display: flex; 14 | align-items: center; 15 | justify-content: space-around; 16 | margin: auto; 17 | } 18 | .header-content div h1{ 19 | font-family: var(--font-family); 20 | width: 70%; 21 | font-weight: bold; 22 | font-size: 48px; 23 | line-height: 105.7%; 24 | color: #FFFFFF; 25 | padding: 1rem; 26 | margin-left: 2rem; 27 | } 28 | .header-content div img{ 29 | width: 17%; 30 | } 31 | .header-slider{ 32 | margin-top: 5rem; 33 | /* background: wheat; */ 34 | color: #FFFFFF; 35 | width: 100%; 36 | position: relative; 37 | display: flex; 38 | flex-direction: column; 39 | justify-content: center; 40 | align-items: center; 41 | } 42 | .header-slider .slider{ 43 | width: 70%; 44 | } 45 | .header-slider h1 { 46 | font-family: var(--font-family); 47 | font-weight: 600; 48 | font-size: 28px; 49 | line-height: 42px; 50 | color: #FFFFFF; 51 | margin-bottom: 1rem; 52 | 53 | } 54 | 55 | .slider .slider-card{ 56 | width: 180px !important; 57 | height: 200px !important; 58 | background: #2A2D3A; 59 | border-radius: 20px; 60 | display: flex !important; 61 | flex-direction: column; 62 | align-items: center; 63 | justify-content: center; 64 | position: relative; 65 | } 66 | .slider-card img{ 67 | border-radius: 50%; 68 | } 69 | .slider-card-number{ 70 | position: absolute; 71 | top: 5.5%; 72 | left: 6.11%; 73 | background: var(--primary-color); 74 | width: 33px; 75 | height: 33px; 76 | border-radius: 50%; 77 | font-weight: 600; 78 | font-size: 16px; 79 | display: flex; 80 | align-items: center; 81 | justify-content: center; 82 | } 83 | .slider-card p{ 84 | font-family: var(--font-family); 85 | font-weight: 600; 86 | font-size: 16px; 87 | line-height: 24px; 88 | color: #FFFFFF; 89 | margin-top: 5px; 90 | } 91 | .slider-card span{ 92 | font-weight: normal !important; 93 | } 94 | 95 | .shake-vertical { 96 | -webkit-animation: shake-vertical 10s cubic-bezier(0.455, 0.030, 0.515, 0.955) 2s infinite both; 97 | animation: shake-vertical 10s cubic-bezier(0.455, 0.030, 0.515, 0.955) 2s infinite both; 98 | } 99 | @-webkit-keyframes shake-vertical { 100 | 0%, 101 | 100% { 102 | -webkit-transform: translateY(0); 103 | transform: translateY(0); 104 | } 105 | 10%, 106 | 30%, 107 | 50%, 108 | 70% { 109 | -webkit-transform: translateY(-8px); 110 | transform: translateY(-8px); 111 | } 112 | 20%, 113 | 40%, 114 | 60% { 115 | -webkit-transform: translateY(8px); 116 | transform: translateY(8px); 117 | } 118 | 80% { 119 | -webkit-transform: translateY(6.4px); 120 | transform: translateY(6.4px); 121 | } 122 | 90% { 123 | -webkit-transform: translateY(-6.4px); 124 | transform: translateY(-6.4px); 125 | } 126 | } 127 | @keyframes shake-vertical { 128 | 0%, 129 | 100% { 130 | -webkit-transform: translateY(0); 131 | transform: translateY(0); 132 | } 133 | 10%, 134 | 30%, 135 | 50%, 136 | 70% { 137 | -webkit-transform: translateY(-8px); 138 | transform: translateY(-8px); 139 | } 140 | 20%, 141 | 40%, 142 | 60% { 143 | -webkit-transform: translateY(8px); 144 | transform: translateY(8px); 145 | } 146 | 80% { 147 | -webkit-transform: translateY(6.4px); 148 | transform: translateY(6.4px); 149 | } 150 | 90% { 151 | -webkit-transform: translateY(-6.4px); 152 | transform: translateY(-6.4px); 153 | } 154 | } 155 | 156 | .slider-img{ 157 | position: relative; 158 | } 159 | .verify{ 160 | position: absolute; 161 | right: 5px; 162 | bottom: 2px; 163 | } 164 | 165 | 166 | /* media */ 167 | @media screen and (max-width: 1600px) { 168 | .header-slider .slider{ 169 | width: 90%; 170 | } 171 | 172 | } 173 | @media screen and (max-width: 1350px) { 174 | .header-slider .slider{ 175 | width: 100%; 176 | } 177 | 178 | .header-content div{ 179 | height: 200px; 180 | } 181 | .header-content div h1{ 182 | font-size: 36px; 183 | line-height: 32px; 184 | /* width: 100%; */ 185 | } 186 | 187 | } 188 | @media screen and (max-width: 550px) { 189 | .slick-prev, .slick-next{ 190 | display: none !important; 191 | } 192 | .header-slider h1{ 193 | font-size: 20px; 194 | line-height: 30px; 195 | } 196 | .slider .slider-card{ 197 | width: 138px !important; 198 | height: 165px !important; 199 | } 200 | .slider-card-number{ 201 | width: 24px; 202 | height: 24px; 203 | } 204 | .slider-card p{ 205 | font-size: 14px; 206 | line-height: 21px; 207 | } 208 | .header-content div{ 209 | height: 143px; 210 | } 211 | .header-content div h1{ 212 | font-size: 20px; 213 | line-height: 24px; 214 | width: 100%; 215 | } 216 | } 217 | @media screen and (max-width: 800px){ 218 | .header-content div img{ 219 | width: 20%; 220 | margin-right: 10px; 221 | } 222 | .header-content div{ 223 | justify-content: unset; 224 | } 225 | .header-content div h1{ 226 | margin-left: 1rem; 227 | } 228 | } 229 | @media screen and (max-width: 650px) { 230 | .header-content h1{ 231 | font-size: 48px; 232 | line-height: 60px; 233 | } 234 | 235 | } 236 | 237 | @media screen and (max-width: 400px){ 238 | .slider .slider-card{ 239 | margin-right: 1rem; 240 | } 241 | .bids{ 242 | padding: 2rem 0px !important; 243 | } 244 | } 245 | @media screen and (max-width: 335px){ 246 | .slider .slider-card{ 247 | margin-right: 0.5rem !important; 248 | } 249 | } -------------------------------------------------------------------------------- /front-end/src/pages/item/Item.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState,useEffect } from 'react'; 2 | import './item.css' 3 | import creator from '../../assets/seller2.png' 4 | import { useParams } from 'react-router-dom'; 5 | import { useWallet } from '@suiet/wallet-kit' 6 | import { TransactionBlock } from '@mysten/sui.js/transactions'; 7 | import * as constant from '../../constant/constant'; 8 | import toast, { Toaster } from 'react-hot-toast'; 9 | 10 | const mapping = { 11 | 0: { targetId: "0", name: "Abstract Smoke Red", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids1.png?raw=true" }, 12 | 1: { targetId: "1", name: "Mountain Landscape", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids2.png?raw=true" }, 13 | 2: { targetId: "2", name: "Paint Colour on Wall", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids3.png?raw=true" }, 14 | 3: { targetId: "3", name: "Abstract Pattern", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids4.png?raw=true" }, 15 | 4: { targetId: "4", name: "White Line Grafiti", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids5.png?raw=true" }, 16 | 5: { targetId: "5", name: "Abstract Triangle", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids6.png?raw=true" }, 17 | 6: { targetId: "6", name: "Lake Landscape", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids7.png?raw=true" }, 18 | 7: { targetId: "7", name: "Blue Red Art", imgAddress: "https://github.com/kasim393/NFT-Marketplace-UI/blob/main/src/assets/bids8.png?raw=true" }, 19 | }; 20 | 21 | 22 | const Item = () => { 23 | let id = useParams().id; 24 | let price = useParams().price; 25 | let owner = useParams().owner; 26 | let type = useParams().type; 27 | 28 | 29 | const packageObjectId = constant.packageObjectId; 30 | const moduleMarketName = constant.moduleMarketName; 31 | 32 | const [data, setData] = useState(null); 33 | const [addressWallet, setAddressWallet] = useState(null); 34 | const [buttonPage,setButtonPage] = useState(null); 35 | 36 | const wallet = useWallet(); 37 | 38 | 39 | 40 | async function getNFT() { 41 | const listNFT = []; 42 | const infoObject = await constant.client.call('sui_getObject', [id,{"showContent": true,"showOwner": true,}]); 43 | console.log(infoObject); 44 | listNFT.push(infoObject.data.content.fields) 45 | setData(listNFT); 46 | 47 | } 48 | 49 | useEffect(()=>{ 50 | console.log("addressWallet",addressWallet) 51 | console.log("owner",owner) 52 | if(wallet.account?.address == owner){ 53 | setButtonPage( 54 |
55 | 56 |
57 | ) 58 | } 59 | else 60 | { 61 | setButtonPage( 62 |
63 | 64 |
65 | ) 66 | } 67 | },[data]) 68 | 69 | useEffect(() => { 70 | if (!wallet.connected) return; 71 | setAddressWallet(wallet.account?.address); 72 | // console.log('connected wallet name: ', wallet.name) 73 | // console.log('account address: ', wallet.account?.address) 74 | // console.log('account publicKey: ', wallet.account?.publicKey) 75 | getNFT(); 76 | 77 | }, [wallet.connected,id]) 78 | 79 | 80 | async function unList(){ 81 | const tx = new TransactionBlock(); 82 | tx.moveCall({ 83 | target: `${packageObjectId}::${moduleMarketName}::delist_and_take`, 84 | typeArguments: [constant.typeArgNFT,constant.suiCoin], 85 | arguments: [tx.pure(constant.marketID),tx.pure(id)], 86 | }); 87 | try{ 88 | const res = await wallet.signAndExecuteTransactionBlock({ 89 | transactionBlock: tx, 90 | }); 91 | console.log(res); 92 | toast.success('Reback NFT success!'); 93 | window.location.href = window.location.origin; 94 | } 95 | catch{ 96 | toast.error('Reback NFT fail!'); 97 | } 98 | } 99 | 100 | async function buy(){ 101 | const tx = new TransactionBlock(); 102 | const value = price; 103 | const [coins] = tx.splitCoins(tx.gas, [ 104 | tx.pure(value), 105 | ]) 106 | 107 | tx.moveCall({ 108 | target: `${packageObjectId}::${moduleMarketName}::buy_and_take`, 109 | typeArguments: [constant.typeArgNFT,constant.suiCoin], 110 | arguments: [tx.pure(constant.marketID),tx.pure(id),coins], 111 | }); 112 | try{ 113 | const res = await wallet.signAndExecuteTransactionBlock({ 114 | transactionBlock: tx, 115 | }); 116 | console.log(res); 117 | toast.success('Buy NFT success!'); 118 | window.location.href = window.location.origin; 119 | } 120 | catch{ 121 | toast.error('Buy NFT fail!'); 122 | } 123 | } 124 | 125 | return ( 126 |
127 |
128 | {data?.map((d) => ( 129 |
130 |
131 | item 132 |
133 |
134 |
135 |

{d.name}

136 |

{price} SUI (transfer fee: 1%)

137 |
138 |
139 |

Creater

140 |
141 | creator 142 |

{owner.substring(0,6)+"..."+owner.substring(owner.length-6,owner.length)}

143 |
144 |
145 |
146 |

{d.description}

147 |
148 | {buttonPage} 149 |
150 |
151 | ))} 152 |
153 | ) 154 | }; 155 | 156 | export default Item; 157 | -------------------------------------------------------------------------------- /front-end/src/pages/bidItem/BidItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState,useEffect } from 'react'; 2 | import './BidItem.css' 3 | import creator from '../../assets/seller2.png' 4 | import { useParams } from 'react-router-dom'; 5 | import { useWallet } from '@suiet/wallet-kit' 6 | import { TransactionBlock } from '@mysten/sui.js/transactions'; 7 | import * as constant from '../../constant/constant'; 8 | import toast, { Toaster } from 'react-hot-toast'; 9 | 10 | const BidItem = () => { 11 | let id = useParams().id; 12 | let price = useParams().price; 13 | let owner = useParams().owner; 14 | let auctionID = useParams().auctionID; 15 | 16 | const packageObjectId = constant.packageObjectId; 17 | const moduleMarketName = constant.moduleMarketName; 18 | 19 | const [data, setData] = useState(null); 20 | const [addressWallet, setAddressWallet] = useState(null); 21 | const [buttonPage,setButtonPage] = useState(null); 22 | const [bidInfo,setbidInfo] = useState(null); 23 | const [priceOfBid,setPriceOfBid] = useState(null); 24 | const wallet = useWallet(); 25 | 26 | 27 | 28 | async function getNFT() { 29 | const listNFT = []; 30 | const resData = await constant.client.call('sui_getObject', 31 | [auctionID, 32 | { 33 | "showType": true, 34 | "showOwner": true, 35 | "showPreviousTransaction": true, 36 | "showContent": true, 37 | }]); 38 | console.log(resData); 39 | if(resData!= null) 40 | { 41 | listNFT.push({ 42 | d:resData.data.content.fields.to_sell.fields, 43 | p:resData.data.content.fields.set_change, 44 | q:resData.data.content.fields.bid_data, 45 | }) 46 | } 47 | setData(listNFT); 48 | console.log('listNFT',listNFT); 49 | } 50 | 51 | useEffect(()=>{ 52 | if(data!= null) 53 | { 54 | if(data[0].d !== null && data[0].q === null){ 55 | setbidInfo(data[0].p +" of "+data[0].p +" times"); 56 | } 57 | else if(data[0].d !== null && data[0].q !== null) 58 | { 59 | setbidInfo(data[0].q?.fields.change+" of "+data[0].p +" times - Highest price:"+data[0].q?.fields.funds); 60 | } 61 | else 62 | { 63 | setbidInfo("Bid is expired"); 64 | }; 65 | } 66 | 67 | 68 | if(addressWallet == owner){ 69 | setButtonPage( 70 |
71 | 72 |
73 | ) 74 | } 75 | else 76 | { 77 | setButtonPage( 78 |
79 | setPriceOfBid(e.target.value)}/> 80 | 81 |
82 | ) 83 | }; 84 | 85 | },[data]); 86 | 87 | 88 | useEffect(() => { 89 | if(addressWallet == owner){ 90 | setButtonPage( 91 |
92 | 93 |
94 | ) 95 | } 96 | else 97 | { 98 | setButtonPage( 99 |
100 | setPriceOfBid(e.target.value)}/> 101 | 102 |
103 | ) 104 | }; 105 | }, [priceOfBid]) 106 | 107 | useEffect(() => { 108 | if (!wallet.connected) return; 109 | setAddressWallet(wallet.account?.address); 110 | // console.log('connected wallet name: ', wallet.name) 111 | // console.log('account address: ', wallet.account?.address) 112 | // console.log('account publicKey: ', wallet.account?.publicKey) 113 | getNFT(); 114 | }, [wallet.connected,id]) 115 | 116 | async function BidNFT(){ 117 | if(priceOfBid!= null && priceOfBid!="") 118 | { 119 | const tx = new TransactionBlock(); 120 | const [coins] = tx.splitCoins(tx.gas, [ 121 | tx.pure(priceOfBid), 122 | ]) 123 | console.log(priceOfBid); 124 | tx.moveCall({ 125 | target: `${packageObjectId}::${moduleMarketName}::bid`, 126 | typeArguments: [constant.typeArgNFT], 127 | arguments: [coins,tx.pure(auctionID)], 128 | }); 129 | try{ 130 | const res = await wallet.signAndExecuteTransactionBlock({ 131 | transactionBlock: tx, 132 | }); 133 | console.log(res); 134 | toast.success('Bid NFT success!'); 135 | window.location.href = window.location.origin; 136 | } 137 | catch{ 138 | toast.error('Bid NFT fail!'); 139 | } 140 | } 141 | } 142 | 143 | return ( 144 |
145 |
146 | {data?.map((d) => ( 147 |
148 |
149 | item 150 |
151 |
152 |
153 |

{d.d.name}

154 |

{bidInfo} (bid fee: 1%)

155 |
156 |
157 |

Creater

158 |
159 | creator 160 |

{owner.substring(0,6)+"..."+owner.substring(owner.length-6,owner.length)}

161 |
162 |
163 |
164 |

{d.d.description}

165 |
166 | {buttonPage} 167 |
168 |
169 | ))} 170 |
171 | ) 172 | }; 173 | 174 | export default BidItem; 175 | -------------------------------------------------------------------------------- /front-end/src/components/Pagination/Pagination.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AiFillHeart, AiOutlineHeart } from "react-icons/ai"; 3 | import { Link } from 'react-router-dom'; 4 | import './Pagination.css' 5 | 6 | const Pagination = (props)=>{ 7 | const { currentPage, maxPageLimit, minPageLimit} = props; 8 | const totalPages = props.totalPages-1; 9 | const data = props.data; 10 | const title = props.title; 11 | const pages = []; 12 | for(let i=1 ; i<=totalPages; i++){ 13 | pages.push(i); 14 | } 15 | 16 | 17 | const handlePrevClick = ()=>{ 18 | props.onPrevClick(); 19 | } 20 | const handleNextClick = ()=>{ 21 | props.onNextClick(); 22 | } 23 | const handlePageClick = (e)=>{ 24 | props.onPageChange(Number(e.target.id)); 25 | } 26 | 27 | const pageNumbers = pages.map(page => { 28 | if(page <= maxPageLimit && page > minPageLimit) { 29 | return( 30 |
  • 32 | {page} 33 |
  • 34 | ); 35 | }else{ 36 | return null; 37 | } 38 | }); 39 | 40 | let pageIncrementEllipses = null; 41 | if(pages.length > maxPageLimit){ 42 | pageIncrementEllipses =
  • 43 | } 44 | let pageDecremenEllipses = null; 45 | if(minPageLimit >=1){ 46 | pageDecremenEllipses =
  • 47 | } 48 | // console.log(props.data); 49 | const renderData = (data)=>{ 50 | if(props.type ==1) 51 | { 52 | return( 53 |
    54 |
    55 |
    56 |

    {title}

    57 |
    58 |
    59 | {data.map((d) => ( 60 |
    61 |
    62 |
    63 | 64 | 65 |

    {d.d.name}

    66 | 67 |
    68 |
    69 |

    {d.p.ask} SUI

    70 |
    71 |
    72 |
    73 | ))} 74 |
    75 |
    76 |
    77 | ) 78 | } 79 | else if(props.type ==2) 80 | { 81 | return( 82 |
    83 |
    84 |
    85 |

    {title}

    86 |
    87 |
    88 | {data.map((d) => ( 89 |
    90 |
    91 |
    92 | 93 | 94 |

    {d.d.name}

    95 | 96 |
    97 |
    98 |

    {d.q==null? d.p.ask:d.q.fields.change} auction times

    99 |

    {d.q==null? "":"Higest price:"+d.q.fields.funds+" SUI"}

    100 |
    101 |
    102 |
    103 | ))} 104 |
    105 |
    106 |
    107 | ) 108 | } 109 | else 110 | { 111 | return( 112 |
    113 |
    114 |
    115 |

    {title}

    116 |
    117 |
    118 | {data?.map((d) => ( 119 |
    120 |
    121 |
    122 | 123 | 124 |

    {d.name}

    125 | 126 |
    127 |
    128 |

    {d.description}

    129 |
    130 |
    131 |
    132 | ))} 133 |
    134 |
    135 |
    136 | ) 137 | } 138 | 139 | 140 | } 141 | 142 | 143 | 144 | return( 145 |
    146 |
    147 | {renderData(data)} 148 |
    149 |
      150 |
    • 151 | 152 |
    • 153 | {pageDecremenEllipses} 154 | {pageNumbers} 155 | {pageIncrementEllipses} 156 |
    • 157 | 158 |
    • 159 |
    160 |
    161 | ) 162 | } 163 | export default Pagination; 164 | -------------------------------------------------------------------------------- /contract/sources/auction_lib.move: -------------------------------------------------------------------------------- 1 | module contract::auction_lib { 2 | use std::option::{Self, Option}; 3 | use sui::coin; 4 | use sui::balance::{Self, Balance}; 5 | use sui::sui::SUI; 6 | use sui::object::{Self, UID}; 7 | use sui::transfer; 8 | use sui::tx_context::{Self,TxContext}; 9 | 10 | friend contract::marketplace; 11 | 12 | /// Stores information about an auction bid. 13 | struct BidData has store { 14 | /// Coin representing the current (highest) bid. 15 | funds: Balance, 16 | /// Address of the highest bidder. 17 | highest_bidder: address, 18 | //count change of bid 19 | change: u64, 20 | } 21 | 22 | /// Maintains the state of the auction owned by a trusted 23 | /// auctioneer. 24 | struct Auction has key { 25 | id: UID, 26 | /// Item to be sold. It only really needs to be wrapped in 27 | /// Option if Auction represents a shared object but we do it 28 | /// for single-owner Auctions for better code re-use. 29 | to_sell: Option, 30 | /// Owner of the time to be sold. 31 | owner: address, 32 | /// Data representing the highest bid (starts with no bid) 33 | bid_data: Option, 34 | set_change: u64, 35 | } 36 | 37 | public(friend) fun auction_owner(auction: &Auction): address { 38 | auction.owner 39 | } 40 | 41 | /// Creates an auction. This is executed by the owner of the asset to be 42 | /// auctioned. 43 | public(friend) fun create_auction( 44 | to_sell: T,set_change:u64, ctx: &mut TxContext 45 | ): Auction { 46 | // A question one might asked is how do we know that to_sell 47 | // is owned by the caller of this entry function and the 48 | // answer is that it's checked by the runtime. 49 | Auction { 50 | id: object::new(ctx), 51 | to_sell: option::some(to_sell), 52 | owner: tx_context::sender(ctx), 53 | bid_data: option::none(), 54 | set_change:set_change, 55 | } 56 | } 57 | 58 | public fun dereference_u64(ref: &u64): u64 { 59 | *ref 60 | } 61 | 62 | #[allow(unused_variable)] 63 | /// Updates the auction based on the information in the bid 64 | /// (update auction if higher bid received and send coin back for 65 | /// bids that are too low). 66 | public fun update_auction( 67 | auction: &mut Auction, 68 | bidder: address, 69 | funds: Balance, 70 | ctx: &mut TxContext, 71 | ) { 72 | if (option::is_none(&auction.bid_data)) { 73 | // first bid 74 | let bid_data = BidData { 75 | funds, 76 | highest_bidder: bidder, 77 | change: auction.set_change, 78 | }; 79 | option::fill(&mut auction.bid_data, bid_data); 80 | } else { 81 | 82 | let prev_bid_data = option::borrow(&auction.bid_data); 83 | if (balance::value(&funds) > balance::value(&prev_bid_data.funds)) { 84 | // a bid higher than currently highest bid received 85 | let new_bid_data = BidData { 86 | funds, 87 | highest_bidder: bidder, 88 | change: dereference_u64(&prev_bid_data.change) - 1 89 | }; 90 | 91 | let s_change = new_bid_data.change; 92 | // update auction to reflect highest bid 93 | let BidData { 94 | funds, 95 | highest_bidder, 96 | change 97 | } = option::swap(&mut auction.bid_data,new_bid_data); 98 | 99 | if(s_change == 0) 100 | { 101 | // transfer previously highest bid to its bidder 102 | send_balance(funds, highest_bidder, ctx); 103 | // end auction send item for bidder 104 | end_shared_auction(auction, ctx); 105 | } 106 | else 107 | { 108 | // a bid is too low - return funds to the bidder 109 | send_balance(funds, bidder, ctx); 110 | }; 111 | 112 | } else { 113 | // a bid is too low - return funds to the bidder 114 | send_balance(funds, bidder, ctx); 115 | } 116 | } 117 | } 118 | 119 | #[allow(unused_variable)] 120 | /// Ends the auction - transfers item to the currently highest 121 | /// bidder or to the original owner if no bids have been placed. 122 | fun end_auction( 123 | to_sell: &mut Option, 124 | owner: address, 125 | bid_data: &mut Option, 126 | ctx: &mut TxContext 127 | ) { 128 | let item = option::extract(to_sell); 129 | if (option::is_some(bid_data)) { 130 | // bids have been placed - send funds to the original item 131 | // owner and the item to the highest bidder 132 | let BidData { 133 | funds, 134 | highest_bidder, 135 | change 136 | } = option::extract(bid_data); 137 | 138 | send_balance(funds, owner, ctx); 139 | transfer::public_transfer(item, highest_bidder); 140 | } else { 141 | // no bids placed - send the item back to the original owner 142 | transfer::public_transfer(item, owner); 143 | }; 144 | } 145 | 146 | #[allow(unused_variable)] 147 | /// Ends auction and destroys auction object (can only be used if 148 | /// Auction is single-owner object) - transfers item to the 149 | /// currently highest bidder or to the original owner if no bids 150 | /// have been placed. 151 | public fun end_and_destroy_auction( 152 | auction: Auction, ctx: &mut TxContext 153 | ) { 154 | let Auction { id, to_sell, owner, bid_data, set_change} = auction; 155 | object::delete(id); 156 | 157 | end_auction(&mut to_sell, owner, &mut bid_data, ctx); 158 | 159 | option::destroy_none(bid_data); 160 | option::destroy_none(to_sell); 161 | } 162 | 163 | /// Ends auction (should only be used if Auction is a shared 164 | /// object) - transfers item to the currently highest bidder or to 165 | /// the original owner if no bids have been placed. 166 | public fun end_shared_auction( 167 | auction: &mut Auction, ctx: &mut TxContext 168 | ) { 169 | end_auction(&mut auction.to_sell, auction.owner, &mut auction.bid_data, ctx); 170 | } 171 | 172 | /// Helper for the most common operation - wrapping a balance and sending it 173 | fun send_balance(balance: Balance, to: address, ctx: &mut TxContext) { 174 | transfer::public_transfer(coin::from_balance(balance, ctx), to) 175 | } 176 | 177 | /// exposes transfer::transfer 178 | public fun transfer(obj: Auction, recipient: address) { 179 | transfer::transfer(obj, recipient) 180 | } 181 | 182 | #[allow(lint(share_owned))] 183 | public fun share_object(obj: Auction) { 184 | transfer::share_object(obj) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /contract/sources/marketplace.move: -------------------------------------------------------------------------------- 1 | module contract::marketplace { 2 | use sui::dynamic_object_field as ofield; 3 | use sui::tx_context::{Self, TxContext}; 4 | use sui::object::{Self, ID, UID}; 5 | use sui::coin::{Self, Coin}; 6 | use sui::bag::{Bag, Self}; 7 | use sui::table::{Table, Self}; 8 | use sui::sui::SUI; 9 | use sui::event; 10 | use sui::transfer; 11 | use contract::auction_lib::{Self, Auction}; 12 | 13 | /// For when amount paid does not match the expected. 14 | const EAmountIncorrect: u64 = 0; 15 | /// For when someone tries to delist without ownership. 16 | const ENotOwner: u64 = 1; 17 | 18 | struct CreateAuction has copy, drop { 19 | sender: address, 20 | } 21 | 22 | struct Bid has copy, drop { 23 | sender: address, 24 | } 25 | 26 | public entry fun create_auction( 27 | bid_market: &mut BidMarket, 28 | to_sell: T, 29 | set_change: u64, 30 | ctx: &mut TxContext) 31 | { 32 | let nft_address = object::id(&to_sell); 33 | let auction = auction_lib::create_auction(to_sell,set_change, ctx); 34 | 35 | event::emit(CreateAuction { 36 | sender: tx_context::sender(ctx) 37 | }); 38 | let item_id = object::id(&auction); 39 | 40 | bag::add(&mut bid_market.items,item_id, nft_address); 41 | auction_lib::share_object(auction); 42 | } 43 | 44 | public entry fun bid(coin: Coin, auction: &mut Auction, ctx: &mut TxContext) { 45 | 46 | event::emit(Bid { 47 | sender: tx_context::sender(ctx), 48 | }); 49 | 50 | auction_lib::update_auction( 51 | auction, 52 | tx_context::sender(ctx), 53 | coin::into_balance(coin), 54 | ctx 55 | ); 56 | } 57 | 58 | /// A shared `Marketplace`. Can be created by anyone using the 59 | /// `create` function. One instance of `Marketplace` accepts 60 | /// only one type of Coin - `COIN` for all its listings. 61 | struct Marketplace has key { 62 | id: UID, 63 | items: Bag, 64 | payments: Table> 65 | } 66 | 67 | /// A shared `Marketplace`. Can be created by anyone using the 68 | /// `create` function. One instance of `Marketplace` accepts 69 | /// only one type of Coin - `COIN` for all its listings. 70 | struct BidMarket has key { 71 | id: UID, 72 | items: Bag, 73 | } 74 | 75 | /// A single listing which contains the listed item and its 76 | /// price in [`Coin`]. 77 | struct Listing has key, store { 78 | id: UID, 79 | ask: u64, 80 | owner: address, 81 | } 82 | 83 | /// Create a new shared Marketplace. 84 | public entry fun create(ctx: &mut TxContext) { 85 | let id = object::new(ctx); 86 | let items = bag::new(ctx); 87 | let payments = table::new>(ctx); 88 | transfer::share_object(Marketplace { 89 | id, 90 | items, 91 | payments 92 | }) 93 | } 94 | 95 | /// Create a new shared Bid market. 96 | public entry fun createBidMarket(ctx: &mut TxContext) { 97 | let id = object::new(ctx); 98 | let items = bag::new(ctx); 99 | transfer::share_object(BidMarket { 100 | id, 101 | items, 102 | }) 103 | } 104 | 105 | 106 | /// List an item at the Marketplace. 107 | public entry fun list( 108 | marketplace: &mut Marketplace, 109 | item: T, 110 | ask: u64, 111 | ctx: &mut TxContext 112 | ) { 113 | let item_id = object::id(&item); 114 | let listing = Listing { 115 | ask, 116 | id: object::new(ctx), 117 | owner: tx_context::sender(ctx), 118 | }; 119 | 120 | ofield::add(&mut listing.id, true, item); 121 | bag::add(&mut marketplace.items, item_id, listing) 122 | } 123 | 124 | /// Internal function to remove listing and get an item back. Only owner can do that. 125 | fun delist( 126 | marketplace: &mut Marketplace, 127 | item_id: ID, 128 | ctx: &TxContext 129 | ): T { 130 | let Listing { 131 | id, 132 | owner, 133 | ask: _, 134 | } = bag::remove(&mut marketplace.items, item_id); 135 | 136 | assert!(tx_context::sender(ctx) == owner, ENotOwner); 137 | 138 | let item = ofield::remove(&mut id, true); 139 | object::delete(id); 140 | item 141 | } 142 | 143 | /// Call [`delist`] and transfer item to the sender. 144 | public entry fun delist_and_take( 145 | marketplace: &mut Marketplace, 146 | item_id: ID, 147 | ctx: &mut TxContext 148 | ) { 149 | let item = delist(marketplace, item_id, ctx); 150 | transfer::public_transfer(item, tx_context::sender(ctx)); 151 | } 152 | 153 | /// Internal function to purchase an item using a known Listing. Payment is done in Coin. 154 | /// Amount paid must match the requested amount. If conditions are met, 155 | /// owner of the item gets the payment and buyer receives their item. 156 | fun buy( 157 | marketplace: &mut Marketplace, 158 | item_id: ID, 159 | paid: Coin, 160 | ): T { 161 | let Listing { 162 | id, 163 | ask, 164 | owner 165 | } = bag::remove(&mut marketplace.items, item_id); 166 | 167 | assert!(ask == coin::value(&paid), EAmountIncorrect); 168 | 169 | // Check if there's already a Coin hanging and merge `paid` with it. 170 | // Otherwise attach `paid` to the `Marketplace` under owner's `address`. 171 | if (table::contains>(&marketplace.payments, owner)) { 172 | coin::join( 173 | table::borrow_mut>(&mut marketplace.payments, owner), 174 | paid 175 | ) 176 | } else { 177 | table::add(&mut marketplace.payments, owner, paid) 178 | }; 179 | 180 | let item = ofield::remove(&mut id, true); 181 | object::delete(id); 182 | item 183 | } 184 | 185 | /// Call [`buy`] and transfer item to the sender. 186 | public entry fun buy_and_take( 187 | marketplace: &mut Marketplace, 188 | item_id: ID, 189 | paid: Coin, 190 | ctx: &mut TxContext 191 | ) { 192 | transfer::public_transfer( 193 | buy(marketplace, item_id, paid), 194 | tx_context::sender(ctx) 195 | ) 196 | } 197 | 198 | /// Internal function to take profits from selling items on the `Marketplace`. 199 | fun take_profits( 200 | marketplace: &mut Marketplace, 201 | ctx: &TxContext 202 | ): Coin { 203 | table::remove>(&mut marketplace.payments, tx_context::sender(ctx)) 204 | } 205 | 206 | #[lint_allow(self_transfer)] 207 | /// Call [`take_profits`] and transfer Coin object to the sender. 208 | public entry fun take_profits_and_keep( 209 | marketplace: &mut Marketplace, 210 | ctx: &mut TxContext 211 | ) { 212 | transfer::public_transfer( 213 | take_profits(marketplace, ctx), 214 | tx_context::sender(ctx) 215 | ) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /front-end/src/pages/DetailItemOwner/DetailItemOwner.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState,useEffect } from 'react'; 2 | import './DetailItemOwner.css' 3 | import creator from '../../assets/seller2.png' 4 | import { useParams } from 'react-router-dom'; 5 | import { useWallet } from '@suiet/wallet-kit' 6 | import { TransactionBlock } from '@mysten/sui.js/transactions'; 7 | import * as constant from '../../constant/constant'; 8 | import toast, { Toaster } from 'react-hot-toast'; 9 | 10 | const DetailItemOwner = () => { 11 | let id = useParams().id; 12 | const wallet = useWallet(); 13 | const [data, setData] = useState(null); 14 | const [addressWallet, setAddressWallet] = useState(null); 15 | const [transferAddress, settransferAddress] = useState(''); 16 | const packageObjectId = constant.packageObjectId; 17 | const moduleName = constant.moduleName; 18 | const moduleMarketName = constant.moduleMarketName; 19 | const [res, setRes] = useState(null); 20 | const [urlEx, seturlEx] = useState(null); 21 | const [numAuction,setNumAuction] = useState(null); 22 | const [NFTPrice,setNFTPrice] = useState(null); 23 | 24 | async function getNFT() { 25 | const listNFT = []; 26 | const infoObject = await constant.client.call('sui_getObject', [id,{"showContent": true}]); 27 | listNFT.push(infoObject.data.content.fields) 28 | //console.log(infoObject); 29 | setData(listNFT); 30 | } 31 | 32 | useEffect(() => { 33 | if (!wallet.connected) return; 34 | setAddressWallet(wallet.account?.address); 35 | // console.log('connected wallet name: ', wallet.name) 36 | // console.log('account address: ', wallet.account?.address) 37 | // console.log('account publicKey: ', wallet.account?.publicKey) 38 | getNFT(); 39 | 40 | }, [wallet.connected]) 41 | 42 | useEffect(() => { 43 | getRespond(); 44 | }, [res]) 45 | 46 | async function getRespond(){ 47 | const event = await constant.client.call('sui_getEvents', [res.digest]); 48 | console.log(event); 49 | const idObj = event[0].parsedJson.object_id; 50 | seturlEx(constant.suiExploreLink+idObj); 51 | } 52 | 53 | async function transferTo(){ 54 | console.log("transferTo", id, addressWallet,transferAddress); 55 | const tx = new TransactionBlock(); 56 | tx.moveCall({ 57 | target: `${packageObjectId}::${moduleName}::transfer`, 58 | arguments: [tx.pure(id),tx.pure(transferAddress)], 59 | }); 60 | try{ 61 | const respond = await wallet.signAndExecuteTransactionBlock({ 62 | transactionBlock: tx, 63 | }); 64 | console.log(respond); 65 | toast.success('Transfer NFT to'+transferAddress+' success!'); 66 | setRes(respond); 67 | window.location.href = window.location.origin + "/ItemOwner"; 68 | } 69 | catch{ 70 | console.log('error'); 71 | } 72 | return; 73 | } 74 | 75 | async function BidNFT(){ 76 | const tx = new TransactionBlock(); 77 | tx.moveCall({ 78 | target: `${packageObjectId}::${moduleMarketName}::create_auction`, 79 | typeArguments: [constant.typeArgNFT,constant.suiCoin], 80 | arguments: [tx.pure(constant.bidMarketID),tx.pure(id),tx.pure(numAuction)], 81 | }); 82 | try{ 83 | const res = await wallet.signAndExecuteTransactionBlock({ 84 | transactionBlock: tx, 85 | }); 86 | console.log(res); 87 | toast.success('Public to bid success!'); 88 | window.location.href = window.location.origin + "/ItemOwner"; 89 | } 90 | catch{ 91 | console.log('error'); 92 | } 93 | } 94 | 95 | async function SaleNFT(){ 96 | const tx = new TransactionBlock(); 97 | tx.moveCall({ 98 | target: `${packageObjectId}::${moduleMarketName}::list`, 99 | typeArguments: [constant.typeArgNFT,constant.suiCoin], 100 | arguments: [tx.pure(constant.marketID),tx.pure(id),tx.pure(NFTPrice)], 101 | }); 102 | try{ 103 | const res = await wallet.signAndExecuteTransactionBlock({ 104 | transactionBlock: tx, 105 | }); 106 | console.log(res); 107 | toast.success('Public to sale success!'); 108 | window.location.href = window.location.origin + "/ItemOwner"; 109 | } 110 | catch{ 111 | console.log('error'); 112 | } 113 | } 114 | 115 | async function burn(){ 116 | console.log("burn", id, addressWallet); 117 | const tx = new TransactionBlock(); 118 | tx.moveCall({ 119 | target: `${packageObjectId}::${moduleName}::burn`, 120 | arguments: [tx.pure(id)], 121 | }); 122 | try{ 123 | const res = await wallet.signAndExecuteTransactionBlock({ 124 | transactionBlock: tx, 125 | }); 126 | console.log(res); 127 | toast.success('Burn NFT success!'); 128 | window.location.href = window.location.origin + "/ItemOwner"; 129 | } 130 | catch{ 131 | console.log('error'); 132 | } 133 | return; 134 | } 135 | 136 | 137 | 138 | return ( 139 |
    140 |
    141 | {data?.map((d) => ( 142 |
    143 |
    144 | item 145 |
    146 |
    147 |
    148 |

    {d.name}

    149 |

    100 SUI (transfer fee: 1%) ‧ 20 of 25 available

    150 |
    151 |
    152 |

    Creater

    153 |
    154 | creator 155 |

    {wallet.account?.address.substring(0,6)+"..."+wallet.account?.address.substring(wallet.account?.address.length-6,wallet.account?.address.length)}

    156 |
    157 |
    158 |
    159 |

    {d.description}

    160 |
    161 |
    162 | setNumAuction(e.target.value)}/> 163 | 164 |
    165 |
    166 | setNFTPrice(e.target.value)}/> 167 | 168 |
    169 |
    170 | settransferAddress(e.target.value)}/> 171 | 172 |
    173 |
    174 | 175 |
    176 |
    177 |
    178 | ))} 179 |
    180 | ) 181 | }; 182 | 183 | export default DetailItemOwner; 184 | -------------------------------------------------------------------------------- /front-end/src/components/nftMint/nftMint.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState,useEffect } from 'react' 2 | import './nftMint.css' 3 | import OpenAI from "openai"; 4 | import { TransactionBlock } from '@mysten/sui.js/transactions'; 5 | import { useWallet } from '@suiet/wallet-kit'; 6 | import toast, { Toaster } from 'react-hot-toast'; 7 | import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; 8 | import * as moment from 'moment'; 9 | import * as constant from '../../constant/constant'; 10 | import { ref, getDownloadURL, uploadBytesResumable } from "firebase/storage"; 11 | import domtoimage from 'dom-to-image'; 12 | 13 | const NFTMint = () => { 14 | const key=constant.OpenAIKey; 15 | const openai = new OpenAI({ apiKey: key , dangerouslyAllowBrowser: true }); 16 | const [data, setData] = useState(null); 17 | const [num, setNum] = useState(0); 18 | const [state, setState] = useState(false); 19 | const randomNumberInRange = (min, max) => { 20 | return Math.floor(Math.random() 21 | * (max - min + 1)) + min; 22 | }; 23 | const wallet = useWallet(); 24 | const packageObjectId = constant.packageObjectId; 25 | const moduleName = constant.moduleName; 26 | 27 | const rpcUrl = getFullnodeUrl('devnet'); 28 | const client = new SuiClient({ url: rpcUrl }); 29 | const [res, setRes] = useState(null); 30 | const [nameNFT, setName] = useState(null); 31 | const [urlEx, seturlEx] = useState(null); 32 | const [imgUrl, setImgUrl] = useState(null); 33 | const [text, setText] = useState(null); 34 | const [progresspercent, setProgresspercent] = useState(0); 35 | const [openAIRes, setopenAIRes] = useState(""); 36 | 37 | async function handleclick(){ 38 | let time = new Date(); 39 | setImgUrl(null); 40 | let formattedDate = (moment(time)).format('YYYYMMDDHHmmss') 41 | 42 | setState(true); 43 | setTimeout(() => { 44 | const image = async () => { 45 | try{ 46 | const a = await openai.images.generate({ prompt: "Creat cute meme or fun meme or fantasy meme",size:"256x256", n: 1, }); 47 | setName("AI_NFT#"+formattedDate); 48 | let urlImage = a.data[0].url; 49 | if(urlImage == null) urlImage = constant.defaultImgURL; 50 | //setData(urlImage); 51 | CreateImage("AI_NFT#"+formattedDate,"Image generateted by for future NFT",urlImage); 52 | toast.success('Mint NFT success!'); 53 | } 54 | catch{ 55 | //setData(constant.defaultImgURL); 56 | setName("AI_NFT#"+formattedDate); 57 | CreateImage("AI_NFT#"+formattedDate,"MEME created by for future NFT",constant.defaultImgURL); 58 | //setData(constant.defaultImgURL); 59 | toast.error('Limmit access mint NFT for Today!'); 60 | } 61 | } 62 | image(); 63 | }, 100); 64 | }; 65 | 66 | async function convertUrlToBase64(imageUrl) { 67 | if(imageUrl != null){ 68 | var img = document.getElementById("myImage"); 69 | console.log(img); 70 | domtoimage.toJpeg(document.getElementById('myImage'), { quality: 0.95 }) 71 | .then(function (dataUrl) { 72 | console.log(dataUrl); 73 | }); 74 | } 75 | } 76 | 77 | async function uploadFireBase(fileName,rootImgURL){ 78 | try { 79 | //const base64Data = await convertUrlToBase64(rootImgURL); 80 | // console.log(base64Data); 81 | // let typeimg = base64Data.split('/')[1].split(';')[0]; 82 | // console.log(typeimg); 83 | // console.log(base64Data.replace('data:image/'+typeimg+';base64,','')); 84 | // const storageRef = ref(constant.storage, `files/${fileName+"."+typeimg}`); 85 | // const uploadTask = uploadBytesResumable(storageRef,Buffer.from(base64Data.replace('data:image/'+typeimg+';base64,',''), "base64") ); 86 | 87 | // uploadTask.on("state_changed", 88 | // (snapshot) => { 89 | // const progress = 90 | // Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100); 91 | // setProgresspercent(progress); 92 | // }, 93 | // (error) => { 94 | // alert(error); 95 | // }, 96 | // () => { 97 | // getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { 98 | // setImgUrl(downloadURL) 99 | // }); 100 | // } 101 | // ); 102 | setImgUrl(rootImgURL); 103 | } catch (error) { 104 | console.log(error.message) 105 | //setError(error.message); 106 | } 107 | } 108 | 109 | useEffect(() => { 110 | if (!wallet.connected) return; 111 | // console.log('connected wallet name: ', wallet.name) 112 | // console.log('account address: ', wallet.account?.address) 113 | // console.log('account publicKey: ', wallet.account?.publicKey) 114 | if(!res){ 115 | getRespond(); 116 | } 117 | 118 | }, [wallet.connected]) 119 | 120 | useEffect(() => { 121 | getRespond(); 122 | }, [res]) 123 | 124 | async function getRespond(){ 125 | const event = await client.call('sui_getEvents', [res.digest]); 126 | console.log(event); 127 | const idObj = event[0].parsedJson.object_id; 128 | seturlEx(constant.suiExploreLink+idObj); 129 | } 130 | 131 | async function CreateImage(name,text,url) { 132 | // let unsubscribe = await client.subscribeEvent({ 133 | // filter: { Package: packageObjectId }, 134 | // onMessage: (event) => { 135 | // console.log("subscribeEvent", JSON.stringify(event, null, 2)) 136 | // } 137 | // }); 138 | // const committeeInfo = await client.call('suix_getOwnedObjects', [wallet.account?.address]); 139 | // console.log(committeeInfo); 140 | // setState(false); 141 | // return 142 | setText(text); 143 | setName(name); 144 | await uploadFireBase(name,url); 145 | 146 | } 147 | 148 | useEffect(async()=>{ 149 | if(imgUrl!=null && state) 150 | { 151 | console.log(nameNFT,imgUrl,text); 152 | const tx = new TransactionBlock(); 153 | tx.moveCall({ 154 | target: `${packageObjectId}::${moduleName}::mint_to_sender`, 155 | arguments: [tx.pure(nameNFT),tx.pure(text),tx.pure(imgUrl)], 156 | }); 157 | try{ 158 | const respond = await wallet.signAndExecuteTransactionBlock({ 159 | transactionBlock: tx, 160 | }); 161 | setRes(respond); 162 | setState(false); 163 | setData(imgUrl); 164 | } 165 | catch{ 166 | setState(false); 167 | } 168 | } 169 | },[imgUrl]) 170 | 171 | async function tryclick(){ 172 | setData(null); 173 | }; 174 | 175 | if(data!= null) 176 | { 177 | return( 178 |
    179 |
    180 |
    181 |

    Congratulations! This is your NFT!

    182 |
    183 |
    184 |
    185 |
    186 |
    187 | 188 |
    189 |
    190 |
    191 |
    {nameNFT}
    192 | 193 |
    194 |
    195 | 196 |
    197 |
    198 | ); 199 | } 200 | 201 | return ( 202 |
    203 |
    204 | 205 |
    206 |
    207 |
    208 |
    209 |
    210 |

    Click Mint button to mint your own NFT

    211 |
    212 | 213 |
    214 |
    215 |
    216 |
    217 |
    218 | 219 | ) 220 | } 221 | 222 | export default NFTMint 223 | --------------------------------------------------------------------------------