├── 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 |
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 |
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 |
298 | )
299 | }
300 |
--------------------------------------------------------------------------------
/src/components/Hero/Hero.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | Flex,
4 | Container,
5 | Heading,
6 | Stack,
7 | Text,
8 | Button,
9 | Icon,
10 | IconProps,
11 | } from "@chakra-ui/react";
12 | import { Link } from "react-router-dom";
13 |
14 | export default function Hero() {
15 | return (
16 |
17 |
23 |
28 | Sharing podcasts{" "}
29 |
30 | made easy
31 |
32 |
33 |
34 | Buzzpod is a platform for sharing podcasts. You can add your own
35 | podcasts and listen to other people's podcasts. Buzzpod is completely
36 | free to use and decentralized.We do not store any data on our
37 | servers.Share your next podcast on Buzzpod
38 |
39 |
40 |
41 |
50 |
51 |
52 |
55 |
56 |
57 |
61 |
62 |
63 |
64 | );
65 | }
66 |
67 | export const Illustration = (props: IconProps) => {
68 | return (
69 |
76 |
82 |
88 |
94 |
100 |
106 |
112 |
118 |
124 |
130 |
136 |
140 |
146 |
150 |
156 |
162 |
166 |
170 |
174 |
178 |
182 |
188 |
194 |
200 |
206 |
212 |
218 |
224 |
230 |
234 |
240 |
246 |
250 |
254 |
258 |
262 |
268 |
274 |
280 |
286 |
292 |
298 |
304 |
310 |
314 |
320 |
326 |
330 |
336 |
342 |
348 |
354 |
360 |
366 |
372 |
378 |
384 |
388 |
392 |
398 |
404 |
410 |
416 |
422 |
428 |
434 |
440 |
446 |
452 |
458 |
464 |
470 |
476 |
482 |
488 |
494 |
500 |
506 |
512 |
518 |
524 |
530 |
536 |
542 |
548 |
554 |
560 |
566 |
572 |
578 |
584 |
588 |
594 |
595 |
601 |
607 |
613 |
619 |
625 |
629 |
635 |
641 |
647 |
651 |
657 |
663 |
669 |
673 |
679 |
685 |
691 |
695 |
701 |
707 |
713 |
717 |
723 |
729 |
735 |
739 |
745 |
751 |
757 |
763 |
767 |
771 |
775 |
779 |
783 |
787 |
791 |
795 |
801 |
805 |
811 |
817 |
823 |
829 |
835 |
836 |
844 |
845 |
846 |
847 |
848 |
856 |
857 |
858 |
859 |
860 |
868 |
869 |
870 |
871 |
879 |
880 |
881 |
882 |
883 |
884 |
885 | );
886 | };
887 |
--------------------------------------------------------------------------------