├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── src ├── pages │ ├── Home │ │ └── Home.jsx │ ├── AddPodcast │ │ └── AddPodcast.jsx │ ├── Podcasts │ │ └── Podcasts.jsx │ └── IndividualPodcast │ │ └── IndividualPodcast.jsx ├── setupTests.js ├── App.test.js ├── components │ ├── ProtectedRoutes.jsx │ ├── Footer │ │ └── Footer.jsx │ ├── Navbar │ │ └── NavBar.jsx │ ├── PodcastsCard │ │ └── Podcastscard.jsx │ ├── Form │ │ └── Form.js │ └── Hero │ │ └── Hero.jsx ├── index.css ├── reportWebVitals.js ├── App.css ├── App.js ├── index.js ├── logo.svg └── utils │ ├── createpodcastabi.json │ └── podcastsabi.json ├── .gitignore ├── contracts ├── Podcasts.sol └── CreatePodcast.sol ├── README.md └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SarveshLimaye/buzzpod/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SarveshLimaye/buzzpod/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SarveshLimaye/buzzpod/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/pages/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Hero from '../../components/Hero/Hero' 3 | 4 | export default function Home() { 5 | return ( 6 |
7 | 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/AddPodcast/AddPodcast.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Form from "../../components/Form/Form" 3 | 4 | export default function AddPodcast() { 5 | return ( 6 |
7 |
8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/components/ProtectedRoutes.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Outlet, Navigate } from "react-router-dom"; 3 | import { useAuth } from "@arcana/auth-react"; 4 | 5 | const ProtectedRoutes = () => { 6 | const { isLoggedIn } = useAuth(); 7 | return
{!isLoggedIn ? : }
; 8 | }; 9 | 10 | export default ProtectedRoutes; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .env 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | display: flex; 4 | flex-direction: column; 5 | min-height: 100vh; 6 | } 7 | 8 | .App-logo { 9 | height: 40vmin; 10 | pointer-events: none; 11 | } 12 | 13 | @media (prefers-reduced-motion: no-preference) { 14 | .App-logo { 15 | animation: App-logo-spin infinite 20s linear; 16 | } 17 | } 18 | 19 | .App-header { 20 | background-color: #282c34; 21 | min-height: 100vh; 22 | display: flex; 23 | flex-direction: column; 24 | align-items: center; 25 | justify-content: center; 26 | font-size: calc(10px + 2vmin); 27 | color: white; 28 | } 29 | 30 | .App-link { 31 | color: #61dafb; 32 | } 33 | 34 | @keyframes App-logo-spin { 35 | from { 36 | transform: rotate(0deg); 37 | } 38 | to { 39 | transform: rotate(360deg); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/Podcasts.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | 6 | contract Podcasts is Ownable { 7 | string public name; 8 | string public description; 9 | string public imageURL; 10 | string public speakers; 11 | address payable createdBy; 12 | string public date; 13 | uint256 public totalListeners; 14 | string public podcastLink; 15 | 16 | constructor( 17 | string memory _name, 18 | string memory _description, 19 | string memory _imageURL, 20 | string memory _speakers, 21 | address payable _createdBy, 22 | string memory _date, 23 | uint256 _totalListeners, 24 | string memory _podcastLink 25 | ) { 26 | name = _name; 27 | description = _description; 28 | imageURL = _imageURL; 29 | speakers = _speakers; 30 | createdBy = _createdBy; 31 | date = _date; 32 | totalListeners = _totalListeners; 33 | podcastLink = _podcastLink; 34 | } 35 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; 2 | import Home from "./pages/Home/Home"; 3 | import Podcasts from "./pages/Podcasts/Podcasts"; 4 | import AddPodcast from "./pages/AddPodcast/AddPodcast"; 5 | import NavBar from "./components/Navbar/NavBar"; 6 | import Footer from "./components/Footer/Footer"; 7 | import "./App.css"; 8 | import ProtectedRoutes from "./components/ProtectedRoutes"; 9 | import IndividualPodcast from "./pages/IndividualPodcast/IndividualPodcast"; 10 | 11 | function App() { 12 | return ( 13 |
14 | 15 | 16 | 17 | } /> 18 | } /> 19 | } /> 20 | }> 21 | } /> 22 | 23 | 24 |
25 | 26 |
27 | ); 28 | } 29 | 30 | export default App; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BuzzPod :rocket: 2 | 3 | BuzzPod is decentralized platform to find and upload podcasts. 4 | 5 | ## TechStack Used :dart: 6 | - React 7 | - Chakra UI 8 | - Arcana 9 | - Solidity 10 | - NFT Port 11 | - ether js 12 | - react-router-dom 13 | - react-toastify 14 | - React-Icons 15 | - Web3.storage 16 | - IPFS 17 | 18 | ## Local Setup 🚧 19 | 20 | 1. Fork the repo. 21 | 2. Clone the repo. 22 | ``` 23 | https://github.com/[YOUR_USER_ACCOUNT]/buzzpod 24 | ``` 25 | 3. Generate API keys for Arcana and Web3.storage 26 | 4. Create .env file at the root of the project and initiate environment variables of the API keys, Refer `.env.example`. 27 | 28 | 29 | 5. Navigate to the clone 30 | ``` 31 | cd buzzpod 32 | ``` 33 | 6. Install dependencies 34 | ``` 35 | yarn 36 | ``` 37 | 7. Start the website locally using 38 | ``` 39 | yarn start 40 | ``` 41 | 42 | ## List of all Smart Contracts deployed on goerli testnet :zap: 43 | 44 | ``` 45 | CreatePodcast:- 0x5BB1458eeeD0148a76Dc48c695cDaA7B5e81EbE2 46 | ``` 47 | 48 | ## List of all Smart Contracts deployed on fvm testnet :zap: 49 | 50 | ``` 51 | CreatePodcast:- 0x9452C28fC02370a15a279f325C84EC14a8278dA3 52 | ``` 53 | 54 | 55 | 56 | ### Do drop a star if you loved this project :star: 57 | 58 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | import { ChakraProvider, extendTheme } from "@chakra-ui/react"; 7 | import { AuthProvider } from "@arcana/auth"; 8 | import { ProvideAuth } from "@arcana/auth-react"; 9 | 10 | const colors = { 11 | brand: { 12 | 50: "#ecefff", 13 | 100: "#cbceeb", 14 | 200: "#a9aed6", 15 | 300: "#888ec5", 16 | 400: "#666db3", 17 | 500: "#4d5499", 18 | 600: "#3c4178", 19 | 700: "#2a2f57", 20 | 800: "#181c37", 21 | 900: "#080819" 22 | } 23 | }; 24 | const config = { 25 | initialColorMode: "dark", 26 | useSystemColorMode: false 27 | }; 28 | 29 | const theme = extendTheme({ colors, config }) 30 | 31 | const provider = new AuthProvider(`${process.env.REACT_APP_ARCANA_APPID}`) 32 | 33 | const root = ReactDOM.createRoot(document.getElementById('root')); 34 | root.render( 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ); 43 | 44 | // If you want to start measuring performance in your app, pass a function 45 | // to log results (for example: reportWebVitals(console.log)) 46 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 47 | reportWebVitals(); 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "buzzpod", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@arcana/auth": "^1.0.1", 7 | "@arcana/auth-react": "^0.0.3", 8 | "@chakra-ui/icons": "^2.0.17", 9 | "@chakra-ui/react": "^2.5.1", 10 | "@emotion/react": "^11.10.6", 11 | "@emotion/styled": "^11.10.6", 12 | "@openzeppelin/contracts": "^4.8.1", 13 | "@testing-library/jest-dom": "^5.14.1", 14 | "@testing-library/react": "^13.0.0", 15 | "@testing-library/user-event": "^13.2.1", 16 | "ethers": "5.6.9", 17 | "framer-motion": "^9.0.4", 18 | "react": "^18.2.0", 19 | "react-audio-player": "^0.17.0", 20 | "react-dom": "^18.2.0", 21 | "react-icons": "^4.7.1", 22 | "react-router-dom": "^6.8.1", 23 | "react-scripts": "5.0.1", 24 | "web-vitals": "^2.1.0", 25 | "web3.storage": "^4.4.0" 26 | }, 27 | "scripts": { 28 | "start": "react-scripts start", 29 | "build": "react-scripts build", 30 | "test": "react-scripts test", 31 | "eject": "react-scripts eject" 32 | }, 33 | "eslintConfig": { 34 | "extends": [ 35 | "react-app", 36 | "react-app/jest" 37 | ] 38 | }, 39 | "browserslist": { 40 | "production": [ 41 | ">0.2%", 42 | "not dead", 43 | "not op_mini all" 44 | ], 45 | "development": [ 46 | "last 1 chrome version", 47 | "last 1 firefox version", 48 | "last 1 safari version" 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Buzzpod 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /contracts/CreatePodcast.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | import "./Podcasts.sol"; 4 | 5 | contract CreatePodcast { 6 | Podcasts[] public _podcasts; 7 | uint256 constant maxLimit = 20; 8 | 9 | event PodcastCreated(Podcasts indexed newpodcast, address indexed owner); 10 | 11 | function podcastscount() public view returns (uint256) { 12 | return _podcasts.length; 13 | } 14 | 15 | function createPodcast( 16 | string memory name, 17 | string memory description, 18 | string memory imageURL, 19 | string memory speakers, 20 | address payable createdBy, 21 | string memory date, 22 | uint256 totalListeners, 23 | string memory podcastLink 24 | ) public { 25 | Podcasts newPodcast = new Podcasts( 26 | name, 27 | description, 28 | imageURL, 29 | speakers, 30 | createdBy, 31 | date, 32 | totalListeners, 33 | podcastLink 34 | ); 35 | _podcasts.push(newPodcast); 36 | emit PodcastCreated(newPodcast, createdBy); 37 | } 38 | 39 | function podcasts( 40 | uint256 limit, 41 | uint256 offset 42 | ) public view returns (Podcasts[] memory coll) { 43 | //logic for pagination 44 | require(offset <= podcastscount(), "offset out of bounds"); 45 | // start our size as difference between total count and offset 46 | uint256 size = podcastscount() - offset; 47 | // size should be the smaller of the count or the limit 48 | size = size < limit ? size : limit; 49 | // size should not exceed the maxLimit 50 | size = size < maxLimit ? size : maxLimit; 51 | // build our collection to return based off of limit and offest 52 | coll = new Podcasts[](size); 53 | for (uint256 i = 0; i < size; i++) { 54 | coll[i] = _podcasts[offset + i]; 55 | } 56 | return coll; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/pages/Podcasts/Podcasts.jsx: -------------------------------------------------------------------------------- 1 | import React,{useState,useEffect} from 'react' 2 | import {Button} from "@chakra-ui/react" 3 | import { ethers } from "ethers"; 4 | import podcastabi from '../../utils/podcastsabi.json' 5 | import createpodcastabi from '../../utils/createpodcastabi.json' 6 | import Podcastscard from '../../components/PodcastsCard/Podcastscard'; 7 | import { Grid, GridItem } from '@chakra-ui/react' 8 | import { useMediaQuery } from '@chakra-ui/react' 9 | import { useAuth } from "@arcana/auth-react"; 10 | 11 | export default function Podcasts() { 12 | const {provider} = useAuth(); 13 | useEffect (()=>{ 14 | const handleClick = () =>{ 15 | setPodcastlist(true); 16 | const prov = new ethers.providers.Web3Provider(provider); 17 | const signer = prov.getSigner(); 18 | const contract = new ethers.Contract( 19 | "0x5BB1458eeeD0148a76Dc48c695cDaA7B5e81EbE2", 20 | createpodcastabi, 21 | signer 22 | ); 23 | const AllPodcasts = contract.podcasts(10,0); 24 | AllPodcasts.then((result) => { 25 | setPodcasts(result); 26 | console.log(result); 27 | }).catch((err) => { 28 | console.log(err); 29 | }); 30 | } 31 | handleClick(); 32 | },[]) 33 | const [podcastlist,setPodcastlist] = useState(false); 34 | const [podcasts,setPodcasts] = useState([]); 35 | const [isLargerThan800] = useMediaQuery('(min-width: 800px)') 36 | 37 | return ( 38 |
39 | {podcasts.length && ( 40 |
41 | {isLargerThan800 ? ( 42 | 43 | {podcasts.map((item,index) => ( 44 | 45 | ))} 46 | 47 | ) : ( 48 | 49 | {podcasts.map((item,index) => ( 50 | 51 | ))} 52 | 53 | )} 54 |
55 | )} 56 |
57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | chakra, 4 | Container, 5 | Stack, 6 | Text, 7 | useColorModeValue, 8 | VisuallyHidden, 9 | } from "@chakra-ui/react"; 10 | import { FaYoutube, FaGithub } from "react-icons/fa"; 11 | import { ReactNode } from "react"; 12 | 13 | const SocialButton = ({ 14 | children, 15 | label, 16 | href, 17 | }: { 18 | children: ReactNode, 19 | label: string, 20 | href: string, 21 | }) => { 22 | return ( 23 | 39 | {label} 40 | {children} 41 | 42 | ); 43 | }; 44 | 45 | export default function Footer() { 46 | return ( 47 | 52 | 61 | 62 | Made with ❤️ by Team Localhost 63 | 64 | 65 | 66 | 67 | 72 | 73 | 74 | 75 | 76 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ); 88 | } 89 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/createpodcastabi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "contract Podcasts", 8 | "name": "newpodcast", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "owner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "PodcastCreated", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "internalType": "uint256", 25 | "name": "", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "_podcasts", 30 | "outputs": [ 31 | { 32 | "internalType": "contract Podcasts", 33 | "name": "", 34 | "type": "address" 35 | } 36 | ], 37 | "stateMutability": "view", 38 | "type": "function" 39 | }, 40 | { 41 | "inputs": [ 42 | { 43 | "internalType": "string", 44 | "name": "name", 45 | "type": "string" 46 | }, 47 | { 48 | "internalType": "string", 49 | "name": "description", 50 | "type": "string" 51 | }, 52 | { 53 | "internalType": "string", 54 | "name": "imageURL", 55 | "type": "string" 56 | }, 57 | { 58 | "internalType": "string", 59 | "name": "speakers", 60 | "type": "string" 61 | }, 62 | { 63 | "internalType": "address payable", 64 | "name": "createdBy", 65 | "type": "address" 66 | }, 67 | { 68 | "internalType": "string", 69 | "name": "date", 70 | "type": "string" 71 | }, 72 | { 73 | "internalType": "uint256", 74 | "name": "totalListeners", 75 | "type": "uint256" 76 | }, 77 | { 78 | "internalType": "string", 79 | "name": "podcastLink", 80 | "type": "string" 81 | } 82 | ], 83 | "name": "createPodcast", 84 | "outputs": [], 85 | "stateMutability": "nonpayable", 86 | "type": "function" 87 | }, 88 | { 89 | "inputs": [ 90 | { 91 | "internalType": "uint256", 92 | "name": "limit", 93 | "type": "uint256" 94 | }, 95 | { 96 | "internalType": "uint256", 97 | "name": "offset", 98 | "type": "uint256" 99 | } 100 | ], 101 | "name": "podcasts", 102 | "outputs": [ 103 | { 104 | "internalType": "contract Podcasts[]", 105 | "name": "coll", 106 | "type": "address[]" 107 | } 108 | ], 109 | "stateMutability": "view", 110 | "type": "function" 111 | }, 112 | { 113 | "inputs": [], 114 | "name": "podcastscount", 115 | "outputs": [ 116 | { 117 | "internalType": "uint256", 118 | "name": "", 119 | "type": "uint256" 120 | } 121 | ], 122 | "stateMutability": "view", 123 | "type": "function" 124 | } 125 | ] -------------------------------------------------------------------------------- /src/utils/podcastsabi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "string", 6 | "name": "_name", 7 | "type": "string" 8 | }, 9 | { 10 | "internalType": "string", 11 | "name": "_description", 12 | "type": "string" 13 | }, 14 | { 15 | "internalType": "string", 16 | "name": "_imageURL", 17 | "type": "string" 18 | }, 19 | { 20 | "internalType": "string", 21 | "name": "_speakers", 22 | "type": "string" 23 | }, 24 | { 25 | "internalType": "address payable", 26 | "name": "_createdBy", 27 | "type": "address" 28 | }, 29 | { 30 | "internalType": "string", 31 | "name": "_date", 32 | "type": "string" 33 | }, 34 | { 35 | "internalType": "uint256", 36 | "name": "_totalListeners", 37 | "type": "uint256" 38 | }, 39 | { 40 | "internalType": "string", 41 | "name": "_podcastLink", 42 | "type": "string" 43 | } 44 | ], 45 | "stateMutability": "nonpayable", 46 | "type": "constructor" 47 | }, 48 | { 49 | "anonymous": false, 50 | "inputs": [ 51 | { 52 | "indexed": true, 53 | "internalType": "address", 54 | "name": "previousOwner", 55 | "type": "address" 56 | }, 57 | { 58 | "indexed": true, 59 | "internalType": "address", 60 | "name": "newOwner", 61 | "type": "address" 62 | } 63 | ], 64 | "name": "OwnershipTransferred", 65 | "type": "event" 66 | }, 67 | { 68 | "inputs": [], 69 | "name": "date", 70 | "outputs": [ 71 | { 72 | "internalType": "string", 73 | "name": "", 74 | "type": "string" 75 | } 76 | ], 77 | "stateMutability": "view", 78 | "type": "function" 79 | }, 80 | { 81 | "inputs": [], 82 | "name": "description", 83 | "outputs": [ 84 | { 85 | "internalType": "string", 86 | "name": "", 87 | "type": "string" 88 | } 89 | ], 90 | "stateMutability": "view", 91 | "type": "function" 92 | }, 93 | { 94 | "inputs": [], 95 | "name": "imageURL", 96 | "outputs": [ 97 | { 98 | "internalType": "string", 99 | "name": "", 100 | "type": "string" 101 | } 102 | ], 103 | "stateMutability": "view", 104 | "type": "function" 105 | }, 106 | { 107 | "inputs": [], 108 | "name": "name", 109 | "outputs": [ 110 | { 111 | "internalType": "string", 112 | "name": "", 113 | "type": "string" 114 | } 115 | ], 116 | "stateMutability": "view", 117 | "type": "function" 118 | }, 119 | { 120 | "inputs": [], 121 | "name": "owner", 122 | "outputs": [ 123 | { 124 | "internalType": "address", 125 | "name": "", 126 | "type": "address" 127 | } 128 | ], 129 | "stateMutability": "view", 130 | "type": "function" 131 | }, 132 | { 133 | "inputs": [], 134 | "name": "podcastLink", 135 | "outputs": [ 136 | { 137 | "internalType": "string", 138 | "name": "", 139 | "type": "string" 140 | } 141 | ], 142 | "stateMutability": "view", 143 | "type": "function" 144 | }, 145 | { 146 | "inputs": [], 147 | "name": "renounceOwnership", 148 | "outputs": [], 149 | "stateMutability": "nonpayable", 150 | "type": "function" 151 | }, 152 | { 153 | "inputs": [], 154 | "name": "speakers", 155 | "outputs": [ 156 | { 157 | "internalType": "string", 158 | "name": "", 159 | "type": "string" 160 | } 161 | ], 162 | "stateMutability": "view", 163 | "type": "function" 164 | }, 165 | { 166 | "inputs": [], 167 | "name": "totalListeners", 168 | "outputs": [ 169 | { 170 | "internalType": "uint256", 171 | "name": "", 172 | "type": "uint256" 173 | } 174 | ], 175 | "stateMutability": "view", 176 | "type": "function" 177 | }, 178 | { 179 | "inputs": [ 180 | { 181 | "internalType": "address", 182 | "name": "newOwner", 183 | "type": "address" 184 | } 185 | ], 186 | "name": "transferOwnership", 187 | "outputs": [], 188 | "stateMutability": "nonpayable", 189 | "type": "function" 190 | } 191 | ] -------------------------------------------------------------------------------- /src/components/Navbar/NavBar.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { 3 | chakra, 4 | Box, 5 | Flex, 6 | useColorModeValue, 7 | VisuallyHidden, 8 | HStack, 9 | Button, 10 | useDisclosure, 11 | VStack, 12 | IconButton, 13 | CloseButton, 14 | Avatar, 15 | } from "@chakra-ui/react"; 16 | import { AiOutlineMenu } from "react-icons/ai"; 17 | import { useAuth } from "@arcana/auth-react"; 18 | import { Link } from "react-router-dom"; 19 | 20 | export default function NavBar() { 21 | const { isLoggedIn, connect, user } = useAuth(); 22 | const bg = useColorModeValue("white", "gray.800"); 23 | const mobileNav = useDisclosure(); 24 | const onConnectClick = async () => { 25 | try { 26 | await connect(); 27 | console.log(user); 28 | } catch (err) { 29 | console.log({ err }); 30 | // Handle error 31 | } 32 | }; 33 | return ( 34 | 35 | 36 | 37 | 38 | 44 | Buzzpod 45 | 46 | 47 | 48 | Buzzpod 49 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 70 | {isLoggedIn ? ( 71 | 77 | 78 | 79 | 80 | 81 | ) : null} 82 | 83 | {!isLoggedIn ? ( 84 | 87 | ) : ( 88 | 89 | )} 90 | 91 | } 99 | onClick={mobileNav.onOpen} 100 | /> 101 | 102 | 117 | 121 | 122 | 125 | 126 | 127 | 130 | 131 | 132 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | ); 142 | } 143 | -------------------------------------------------------------------------------- /src/components/PodcastsCard/Podcastscard.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { Box, Flex, Icon, Image, chakra } from "@chakra-ui/react"; 3 | import { ethers } from "ethers"; 4 | import { Web3Storage } from "web3.storage"; 5 | import { 6 | MdEmail, 7 | MdHeadset, 8 | MdLocationOn, 9 | MdSpeakerPhone, 10 | MdPeopleAlt, 11 | } from "react-icons/md"; 12 | import { BsFillBriefcaseFill } from "react-icons/bs"; 13 | import podcastsabi from "../../utils/podcastsabi.json"; 14 | import { Grid, GridItem } from "@chakra-ui/react"; 15 | import { useMediaQuery } from "@chakra-ui/react"; 16 | import { useAuth } from "@arcana/auth-react"; 17 | import { Button, ButtonGroup } from "@chakra-ui/react"; 18 | import { useNavigate } from "react-router-dom"; 19 | 20 | const Podcastscard = ({ individualPodcast }) => { 21 | const [name, setName] = useState(""); 22 | const [description, setDescription] = useState(""); 23 | const [imageurl, setImageurl] = useState(""); 24 | const [speakers, setSpeakers] = useState(""); 25 | const [createdby, setCreatedby] = useState(""); 26 | const [date, setDate] = useState(false); 27 | const [listeners, setListeners] = useState(""); 28 | const [podcastlink, setPodcastlink] = useState(""); 29 | const [isLargerThan800] = useMediaQuery("(min-width: 800px)"); 30 | const navigate = useNavigate(); 31 | const { provider } = useAuth(); 32 | 33 | const handleClick = () => { 34 | navigate(`podcast/${individualPodcast}`); 35 | }; 36 | 37 | useEffect(() => { 38 | const getPodcastDetails = async () => { 39 | const prov = new ethers.providers.Web3Provider(provider); 40 | const signer = prov.getSigner(); 41 | const contract = new ethers.Contract( 42 | individualPodcast, 43 | podcastsabi, 44 | signer 45 | ); 46 | contract 47 | .name() 48 | .then((result) => { 49 | setName(result); 50 | }) 51 | .catch((err) => { 52 | console.log(err); 53 | }); 54 | 55 | contract 56 | .description() 57 | .then((result) => { 58 | setDescription(result); 59 | }) 60 | .catch((err) => { 61 | console.log(err); 62 | }); 63 | 64 | contract 65 | .imageURL() 66 | .then((result) => { 67 | setImageurl(result); 68 | }) 69 | .catch((err) => { 70 | console.log(err); 71 | }); 72 | 73 | contract 74 | .speakers() 75 | .then((result) => { 76 | setSpeakers(result); 77 | }) 78 | .catch((err) => { 79 | console.log(err); 80 | }); 81 | 82 | contract 83 | .date() 84 | .then((result) => { 85 | setDate(result); 86 | }) 87 | .catch((err) => { 88 | console.log(err); 89 | }); 90 | 91 | contract 92 | .totalListeners() 93 | .then((result) => { 94 | setListeners(result); 95 | }) 96 | .catch((err) => { 97 | console.log(err); 98 | }); 99 | }; 100 | getPodcastDetails(); 101 | }, []); 102 | return ( 103 | 104 | 121 | avatar 133 | 134 | 135 | 136 | 137 | 138 | {date} 139 | 140 | 141 | 142 | 143 | 151 | {name} 152 | 153 | 154 | 164 | {description} 165 | 166 | 167 | 175 | 176 | 177 | 178 | {speakers} 179 | 180 | 181 | 189 | 190 | 191 | 192 | 100+ 193 | 194 | 195 | 196 | 204 | 207 | 208 | 209 | 210 | 211 | ); 212 | }; 213 | 214 | export default Podcastscard; 215 | -------------------------------------------------------------------------------- /src/pages/IndividualPodcast/IndividualPodcast.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | chakra, 4 | Container, 5 | Stack, 6 | Text, 7 | Image, 8 | Flex, 9 | VStack, 10 | Button, 11 | Heading, 12 | SimpleGrid, 13 | StackDivider, 14 | useColorModeValue, 15 | VisuallyHidden, 16 | List, 17 | ListItem, 18 | } from "@chakra-ui/react"; 19 | import { FaInstagram, FaTwitter, FaYoutube } from "react-icons/fa"; 20 | import { MdLocalShipping } from "react-icons/md"; 21 | import React, { useEffect, useState } from "react"; 22 | import { ethers } from "ethers"; 23 | import { Web3Storage } from "web3.storage"; 24 | import podcastsabi from "../../utils/podcastsabi.json"; 25 | import { useAuth } from "@arcana/auth-react"; 26 | import { useMediaQuery } from "@chakra-ui/react"; 27 | import { useParams } from "react-router-dom"; 28 | import ReactAudioPlayer from "react-audio-player"; 29 | 30 | export default function IndividualPodcast() { 31 | const [name, setName] = useState(""); 32 | const [description, setDescription] = useState(""); 33 | const [imageurl, setImageurl] = useState(""); 34 | const [speakers, setSpeakers] = useState(""); 35 | const [createdby, setCreatedby] = useState(""); 36 | const [date, setDate] = useState(false); 37 | const [listeners, setListeners] = useState("1000+"); 38 | const [podcastlink, setPodcastlink] = useState(""); 39 | const [isLargerThan800] = useMediaQuery("(min-width: 800px)"); 40 | const { provider } = useAuth(); 41 | 42 | let { id } = useParams(); 43 | // console.log(`id is : ${id}`); 44 | 45 | useEffect(() => { 46 | const getPodcastDetails = async () => { 47 | const prov = new ethers.providers.Web3Provider(provider); 48 | const signer = prov.getSigner(); 49 | const contract = new ethers.Contract(id, podcastsabi, signer); 50 | setPodcastlink("QmfGGyzHiDerKuJomu5ip2rpaNvQBpgJJ4N7oWjcKx7Am7"); 51 | // console.log(`final podcast link: ipfs.io/ipfs/${podcastlink}`); 52 | contract 53 | .name() 54 | .then((result) => { 55 | setName(result); 56 | }) 57 | .catch((err) => { 58 | console.log(err); 59 | }); 60 | 61 | contract 62 | .description() 63 | .then((result) => { 64 | setDescription(result); 65 | }) 66 | .catch((err) => { 67 | console.log(err); 68 | }); 69 | 70 | contract 71 | .imageURL() 72 | .then((result) => { 73 | setImageurl(result); 74 | }) 75 | .catch((err) => { 76 | console.log(err); 77 | }); 78 | 79 | contract 80 | .speakers() 81 | .then((result) => { 82 | setSpeakers(result); 83 | }) 84 | .catch((err) => { 85 | console.log(err); 86 | }); 87 | 88 | contract 89 | .date() 90 | .then((result) => { 91 | setDate(result); 92 | }) 93 | .catch((err) => { 94 | console.log(err); 95 | }); 96 | }; 97 | getPodcastDetails(); 98 | }, []); 99 | 100 | return ( 101 | 102 | 107 | 108 | {"podcast 118 | 119 | 120 | 121 | 126 | {name} 127 | 128 | 133 | {speakers} 134 | 135 | 136 | 137 | 144 | } 145 | > 146 | 147 | {description} 148 | 149 | 150 | 157 | Features 158 | 159 | 160 | 161 | 162 | Date 163 | Listeners Speakers 164 | 165 | 166 | {date} 167 | {listeners} 168 | {speakers} 169 | 170 | 171 | 172 | 173 | 177 | 178 | 179 | 180 | 196 | 197 | 198 | 199 | ); 200 | } 201 | -------------------------------------------------------------------------------- /src/components/Form/Form.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react" 2 | import { 3 | Button, 4 | Box, 5 | SimpleGrid, 6 | GridItem, 7 | chakra, 8 | Stack, 9 | Input, 10 | Textarea, 11 | FormHelperText, 12 | FormControl, 13 | FormLabel, 14 | } from "@chakra-ui/react" 15 | import { useAuth } from "@arcana/auth-react"; 16 | import createPodcastabi from "../../utils/createpodcastabi.json"; 17 | import { ethers } from "ethers"; 18 | import { Web3Storage } from "web3.storage" 19 | 20 | export default function Form() { 21 | const [title, setTitle] = useState("") 22 | const [speaker, setSpeaker] = useState("") 23 | const [description, setDescription] = useState("") 24 | const [date, setDate] = useState("") 25 | const [cover, setCover] = useState("") 26 | const [audio, setAudio] = useState("") 27 | const [covercid, setCovercid] = useState("") 28 | const [audiocid, setAudiocid] = useState("") 29 | const { provider,user } = useAuth() 30 | 31 | 32 | console.log(user) 33 | 34 | function makeStorageClient() { 35 | return new Web3Storage({ token: process.env.REACT_APP_FILECOIN_TOKEN }) 36 | } 37 | 38 | async function storeCover(files) { 39 | const client = makeStorageClient() 40 | const cid = await client.put(files) 41 | console.log("stored files with cid:", cid) 42 | setCovercid(cid) 43 | return cid 44 | } 45 | 46 | async function storeAudio(files) { 47 | const client = makeStorageClient() 48 | const cid = await client.put(files) 49 | console.log("stored files with cid:", cid) 50 | setAudiocid(cid) 51 | return cid 52 | } 53 | 54 | function onSubmitCover() { 55 | let cidOfCover = storeCover(cover) 56 | console.log(cidOfCover) 57 | } 58 | 59 | function onSubmitAudio() { 60 | let cidOfAudio = storeAudio(audio) 61 | console.log(cidOfAudio) 62 | } 63 | 64 | const onSubmit = async (e) => { 65 | e.preventDefault() 66 | const prov = new ethers.providers.Web3Provider(provider); 67 | const signer = prov.getSigner() 68 | const contract = new ethers.Contract( 69 | "0x5BB1458eeeD0148a76Dc48c695cDaA7B5e81EbE2", 70 | createPodcastabi, 71 | signer 72 | ) 73 | const account = user?.address 74 | const tx = await contract.createPodcast( 75 | title, 76 | description, 77 | covercid, 78 | speaker, 79 | account, 80 | date, 81 | 0, 82 | audiocid 83 | ) 84 | 85 | console.log(tx) 86 | } 87 | 88 | return ( 89 |
90 | 97 | 98 | 110 | 116 | 123 | 135 | 136 | 137 | 145 | Title 146 | 147 | setTitle(e.target.value)} 153 | /> 154 | 155 | 156 | 157 | 158 | 159 | 167 | Speaker Name 168 | 169 | setSpeaker(e.target.value)} 175 | /> 176 | 177 | 178 | 179 |
180 | 181 | 190 | Description 191 | 192 |