├── cypress.env.example.json ├── .prettierignore ├── src ├── .DS_Store ├── components │ ├── project │ │ ├── index.js │ │ ├── firstGiveBadge.js │ │ ├── cancelledModal.js │ │ └── updatesTab.js │ ├── create-project-form │ │ ├── modals │ │ │ ├── index.js │ │ │ ├── LocationInputModal.js │ │ │ ├── CloseModal.js │ │ │ └── DescriptionInstructionModal.js │ │ ├── inputs │ │ │ ├── index.js │ │ │ ├── ProjectNameInput.js │ │ │ ├── ProjectAdminInput.js │ │ │ └── ProjectCategotyInput.js │ │ └── utils.js │ ├── user │ │ ├── index.js │ │ ├── userDonations.js │ │ ├── profileView.js │ │ ├── userProjects.js │ │ └── profileHeader.js │ ├── torus │ │ ├── login.js │ │ └── loginButton.js │ ├── avatar.js │ ├── content │ │ ├── Logo.js │ │ ├── HeroSideImage.js │ │ ├── HeroImage.js │ │ ├── JoinPageHero.js │ │ └── SocialNetworks.js │ ├── global.css │ ├── home │ │ ├── MediumFeed.js │ │ └── HomeTopProjects.js │ ├── richTextViewer.js │ ├── loadingModal.js │ ├── modal.js │ ├── image.js │ ├── donateForm.js │ ├── animations │ │ ├── confetti │ │ │ └── index.js │ │ └── subscribed │ │ │ └── index.js │ ├── copyToClipboard.js │ ├── dialog.js │ ├── account │ │ ├── AccountBody.js │ │ ├── projectEdition │ │ │ └── confirmationModal.js │ │ ├── AccountTop.js │ │ └── index.js │ ├── confirmationModal.js │ ├── toast.js │ ├── donate │ │ ├── onlyCrypto_old.js │ │ └── inProgressModal.js │ ├── notification.js │ ├── seo.js │ ├── tooltip.js │ ├── signInMetamaskModal.js │ └── richTextInput.js ├── images │ ├── arcs.png │ ├── avatar.jpg │ ├── popup1.png │ ├── no_funds.png │ ├── coming-soon.png │ ├── exclamation.png │ ├── gatsby-icon.png │ ├── giveth_bg.jpg │ ├── placeholder.png │ ├── corner-leave.png │ ├── info_outline.png │ ├── tree-planting.jpg │ ├── worried_woman.png │ ├── xDAI_ETH_icon.png │ ├── background-gas.png │ ├── co2ken-logo-full.png │ ├── coming-soon-gear.png │ ├── giverBadge@40x40.png │ ├── powered-by-torus.png │ ├── giveth-logo-white.png │ ├── giveth-team-image.png │ ├── giveth-test-image.png │ ├── incomplete_profile.png │ ├── logos │ │ ├── co2ken-logo.png │ │ ├── giveth-logo.jpg │ │ └── metamask-fox.png │ ├── no-image-available.jpg │ ├── people-stretching.png │ ├── decorator-exclamation.png │ ├── decorator-raised-hands.png │ ├── decorator-raised-one-hand.png │ ├── icon-vertical-line.svg │ ├── decorator-a.svg │ ├── svg │ │ ├── general │ │ │ ├── left-arrow.svg │ │ │ ├── dropdown-arrow.svg │ │ │ ├── search-icon.svg │ │ │ └── decorators │ │ │ │ └── tooltip.svg │ │ ├── create │ │ │ ├── projectImageGallery2.svg │ │ │ ├── projectImageGallery3.svg │ │ │ └── projectImageGallery4.svg │ │ └── donation │ │ │ └── qr.svg │ ├── decorator-c.svg │ ├── icon-heart.svg │ ├── decorator-cloud1.svg │ ├── decorator-cloud2.svg │ ├── decorator-b.svg │ ├── decorator-clouds.svg │ ├── decorator-fizzy-square.svg │ ├── decorator-fizzy-square-rotated.svg │ ├── decorator-elements.svg │ ├── giveth-logo-blue.svg │ ├── giveth-logo-purple.svg │ ├── icon-search.svg │ ├── icon-share.svg │ ├── icon-user.svg │ ├── icon-question-mark.svg │ ├── decorator-leaf.svg │ ├── giveth-side-image.svg │ ├── icon-streamline-gas.svg │ └── decorator-circles.svg ├── gatsby-plugin-theme-ui │ └── index.js ├── contextProvider │ ├── globalProvider.js │ ├── popupProvider.js │ ├── projectProvider.js │ └── useLocalStorage.js ├── apollo │ ├── wrapRootElement.js │ ├── client.js │ └── gql │ │ ├── auth.js │ │ └── donations.js ├── content │ ├── co2ken.md │ └── giveth.md ├── utils │ ├── useIsClient.js │ ├── useComponentVisible.js │ └── constants.js ├── pages │ ├── account.js │ ├── 404.js │ ├── iframe.tsx │ ├── faq.js │ ├── join.js │ ├── donate.js │ ├── my-account │ │ └── projects.js │ ├── project │ │ └── [slug].js │ └── user.js ├── Logger.js ├── services │ ├── wallet.js │ ├── ethersSigner.js │ ├── project.js │ ├── auth.js │ ├── donation.ts │ ├── token.js │ └── onBoard.js ├── templates │ ├── project.js │ └── donate.js └── entities │ └── user.ts ├── static ├── avatar.jpg └── assets │ ├── tokens │ ├── HNY.png │ ├── PAN.png │ ├── AGVE.png │ ├── STAKE.png │ ├── WETH.png │ ├── WXDAI.png │ └── XDAI.png │ └── create │ ├── projectImageGallery2.svg │ ├── projectImageGallery3.svg │ └── projectImageGallery4.svg ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── e2e │ │ ├── popup.spec.js │ │ ├── donate.spec.js │ │ ├── soft-launch-warnings.spec.js │ │ └── cookies.spec.js ├── support │ ├── index.js │ └── commands.js └── plugins │ └── index.js ├── .prettierrc ├── gatsby-browser.js ├── gatsby-ssr.js ├── issue_template.md ├── .vscode └── settings.json ├── tsconfig.json ├── .env.example ├── siteMetaData.js ├── netlify.toml ├── .gitignore ├── giveth2-positonic-full-stack.code-workspace └── giveth2-full-stack.code-workspace /cypress.env.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "CYPRESS_USER_LOCAL_TOKEN": "" 3 | } -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /src/components/project/index.js: -------------------------------------------------------------------------------- 1 | export { ProjectDonatorView } from './donatorView' 2 | -------------------------------------------------------------------------------- /static/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/avatar.jpg -------------------------------------------------------------------------------- /src/images/arcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/arcs.png -------------------------------------------------------------------------------- /src/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/avatar.jpg -------------------------------------------------------------------------------- /src/images/popup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/popup1.png -------------------------------------------------------------------------------- /src/images/no_funds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/no_funds.png -------------------------------------------------------------------------------- /src/images/coming-soon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/coming-soon.png -------------------------------------------------------------------------------- /src/images/exclamation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/exclamation.png -------------------------------------------------------------------------------- /src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /src/images/giveth_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/giveth_bg.jpg -------------------------------------------------------------------------------- /src/images/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/placeholder.png -------------------------------------------------------------------------------- /src/images/corner-leave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/corner-leave.png -------------------------------------------------------------------------------- /src/images/info_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/info_outline.png -------------------------------------------------------------------------------- /src/images/tree-planting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/tree-planting.jpg -------------------------------------------------------------------------------- /src/images/worried_woman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/worried_woman.png -------------------------------------------------------------------------------- /src/images/xDAI_ETH_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/xDAI_ETH_icon.png -------------------------------------------------------------------------------- /static/assets/tokens/HNY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/HNY.png -------------------------------------------------------------------------------- /static/assets/tokens/PAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/PAN.png -------------------------------------------------------------------------------- /src/images/background-gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/background-gas.png -------------------------------------------------------------------------------- /src/images/co2ken-logo-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/co2ken-logo-full.png -------------------------------------------------------------------------------- /src/images/coming-soon-gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/coming-soon-gear.png -------------------------------------------------------------------------------- /src/images/giverBadge@40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/giverBadge@40x40.png -------------------------------------------------------------------------------- /src/images/powered-by-torus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/powered-by-torus.png -------------------------------------------------------------------------------- /static/assets/tokens/AGVE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/AGVE.png -------------------------------------------------------------------------------- /static/assets/tokens/STAKE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/STAKE.png -------------------------------------------------------------------------------- /static/assets/tokens/WETH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/WETH.png -------------------------------------------------------------------------------- /static/assets/tokens/WXDAI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/WXDAI.png -------------------------------------------------------------------------------- /static/assets/tokens/XDAI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/static/assets/tokens/XDAI.png -------------------------------------------------------------------------------- /src/images/giveth-logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/giveth-logo-white.png -------------------------------------------------------------------------------- /src/images/giveth-team-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/giveth-team-image.png -------------------------------------------------------------------------------- /src/images/giveth-test-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/giveth-test-image.png -------------------------------------------------------------------------------- /src/images/incomplete_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/incomplete_profile.png -------------------------------------------------------------------------------- /src/images/logos/co2ken-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/logos/co2ken-logo.png -------------------------------------------------------------------------------- /src/images/logos/giveth-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/logos/giveth-logo.jpg -------------------------------------------------------------------------------- /src/images/logos/metamask-fox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/logos/metamask-fox.png -------------------------------------------------------------------------------- /src/images/no-image-available.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/no-image-available.jpg -------------------------------------------------------------------------------- /src/images/people-stretching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/people-stretching.png -------------------------------------------------------------------------------- /src/images/decorator-exclamation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/decorator-exclamation.png -------------------------------------------------------------------------------- /src/images/decorator-raised-hands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/decorator-raised-hands.png -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8000/", 3 | "screenshotOnRunFailure": false, 4 | "videoUploadOnPasses": false 5 | } 6 | -------------------------------------------------------------------------------- /src/images/decorator-raised-one-hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Giveth/giveth-gatsby/HEAD/src/images/decorator-raised-one-hand.png -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "semi": false, 4 | "singleQuote": true, 5 | "jsxSingleQuote": true, 6 | "trailingComma": "none", 7 | "printWidth": 80, 8 | "tabWidth": 2 9 | } 10 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | export { wrapRootElement } from './src/apollo/wrapRootElement' 7 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | export { wrapRootElement } from './src/apollo/wrapRootElement' 8 | -------------------------------------------------------------------------------- /src/components/create-project-form/modals/index.js: -------------------------------------------------------------------------------- 1 | export { CloseModal } from './CloseModal' 2 | export { DescriptionInstructionModal } from './DescriptionInstructionModal' 3 | export { LocationInputModal } from './LocationInputModal' 4 | -------------------------------------------------------------------------------- /src/components/user/index.js: -------------------------------------------------------------------------------- 1 | export { PublicProfileView } from './profileView' 2 | export { ProfileHeader } from './profileHeader' 3 | export { UserProjects } from './userProjects' 4 | export { UserDonations } from './userDonations' 5 | -------------------------------------------------------------------------------- /src/images/icon-vertical-line.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/gatsby-plugin-theme-ui/index.js: -------------------------------------------------------------------------------- 1 | import giveth from './sites/giveth' 2 | import co2ken from './sites/co2ken' 3 | 4 | let theme 5 | 6 | if (process.env.GATSBY_SITE_ID === 'giveth') { 7 | theme = giveth 8 | } else { 9 | theme = co2ken 10 | } 11 | export default theme 12 | -------------------------------------------------------------------------------- /src/images/decorator-a.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | ## 📋 Anything to add? 2 | 3 | 4 | ## ⏰ Urgency/Deadline/Blockers? 5 | 6 | 7 | ## ❓ Why is it important? 8 | 9 | 10 | ## 🎉 Subtasks 11 | 12 | - [ ] 13 | - [ ] 14 | - [ ] 15 | 16 | ## 🤼‍ Reviewer 17 | 18 | @ 19 | 20 | ## 🔗 Work doc - inspirational links 21 | -------------------------------------------------------------------------------- /src/components/user/userDonations.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text, Flex } from 'theme-ui' 3 | import DonationsTable from './donationsTable' 4 | 5 | export const UserDonations = props => { 6 | return ( 7 | 8 | 9 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /src/contextProvider/globalProvider.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ProjectProvider from './projectProvider' 3 | 4 | const GlobalProvider = props => { 5 | return ( 6 | <> 7 | {props.children} 8 | 9 | ) 10 | } 11 | 12 | export default GlobalProvider 13 | -------------------------------------------------------------------------------- /src/apollo/wrapRootElement.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | // import { ApolloProvider } from '@apollo/client' 3 | import { ApolloProvider } from '@apollo/client' 4 | import { client } from './client' 5 | 6 | export const wrapRootElement = ({ element }) => ( 7 | {element} 8 | ) 9 | -------------------------------------------------------------------------------- /src/content/co2ken.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: 'co2ken-home' 3 | mainHead: 'Sustainable fundraising for' 4 | headBold: 'carbon & social impact' 5 | mainText: 'Our mission is to connect projects, and project developers with the funds they need in order to put carbon in the ground' 6 | mainButton: 'Take action' 7 | mainButtonText: 'Fund a carbon project now' 8 | --- 9 | -------------------------------------------------------------------------------- /src/utils/useIsClient.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | const useIsClient = () => { 4 | const [isClient, setClient] = useState(false) 5 | const key = isClient ? 'client' : 'server' 6 | 7 | useEffect(() => { 8 | setClient(true) 9 | }, []) 10 | 11 | return { isClient, key } 12 | } 13 | 14 | export default useIsClient 15 | -------------------------------------------------------------------------------- /src/images/svg/general/left-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/pages/account.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import AccountIndex from '../components/account' 3 | import Seo from '../components/seo' 4 | import Layout from '../components/layout' 5 | 6 | const AccountPage = props => { 7 | return ( 8 | 9 | 10 | 11 | 12 | ) 13 | } 14 | 15 | export default AccountPage 16 | -------------------------------------------------------------------------------- /src/images/decorator-c.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {// Set the default 2 | "editor.formatOnSave": true, 3 | // Enable per-language linting for standardJS (typescript still missing here) 4 | "[javascript]": { 5 | "editor.formatOnSave": true, 6 | "editor.defaultFormatter": "numso.prettier-standard-vscode" 7 | }, 8 | "[javascriptreact]": { 9 | "editor.defaultFormatter": "numso.prettier-standard-vscode" 10 | }, 11 | } -------------------------------------------------------------------------------- /cypress/integration/e2e/popup.spec.js: -------------------------------------------------------------------------------- 1 | describe('Test wallet popup', () => { 2 | it('Should open the wallet popup when wanting to create a project', () => { 3 | cy.visit('/') 4 | cy.get('button') 5 | .contains(/create a project/i) 6 | .click() 7 | cy.wait(3000) 8 | cy.contains(/close/i).should('exist') 9 | cy.contains(/close/i).click() 10 | cy.contains(/close/i).should('not.exist') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /src/components/torus/login.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useWallet } from '../../contextProvider/WalletProvider' 3 | import LoginButton from './loginButton' 4 | import UserDetails from './userDetails' 5 | 6 | const Login = () => { 7 | const { isLoggedIn } = useWallet() 8 | 9 | if (!isLoggedIn) { 10 | return 11 | } else { 12 | return 13 | } 14 | } 15 | export default Login 16 | -------------------------------------------------------------------------------- /src/images/icon-heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Layout from '../components/layout' 4 | import Seo from '../components/seo' 5 | 6 | const NotFoundPage = props => { 7 | console.log({ props }) 8 | 9 | return ( 10 | 11 | 12 |

NOT FOUND

13 |

You just hit a route that doesn't exist... the sadness.

14 |
15 | ) 16 | } 17 | 18 | export default NotFoundPage 19 | -------------------------------------------------------------------------------- /src/Logger.js: -------------------------------------------------------------------------------- 1 | import * as Sentry from '@sentry/gatsby' 2 | 3 | if (typeof window === 'object') { 4 | // const sentryId = process.env.SENTRY_ID 5 | const sentryId = 'de31cb89ac0045afbb9d28322cc9c040@o510515' 6 | 7 | Sentry.init({ 8 | dsn: `https://${sentryId}.ingest.sentry.io/5606310`, 9 | tracesSampleRate: 1.0, // james: look at dropping this, 10 | release: 'giveth-dapp@' + process.env.npm_package_version 11 | }) 12 | } 13 | 14 | export default Sentry 15 | -------------------------------------------------------------------------------- /src/components/avatar.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Avatar } from 'theme-ui' 3 | import Jdenticon from 'react-jdenticon' 4 | import 'react-toastify/dist/ReactToastify.css' 5 | 6 | export default function CustomAvatar({ img, address = 'none', size }) { 7 | return ( 8 | <> 9 | {img ? ( 10 | 11 | ) : ( 12 | 13 | )} 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/images/decorator-cloud1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/images/decorator-cloud2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/images/decorator-b.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/pages/iframe.tsx: -------------------------------------------------------------------------------- 1 | // Gatsby supports TypeScript natively! 2 | import React from "react" 3 | import { PageProps, Link } from "gatsby" 4 | 5 | import Layout from "../components/layout" 6 | import Seo from "../components/seo" 7 | 8 | const iFramePage = (props: PageProps) => ( 9 | 10 | 11 |

Hi from the second page

12 |

Welcome to page 2 ({props.path})

13 | Go back to the homepage 14 |
15 | ) 16 | 17 | export default iFramePage 18 | -------------------------------------------------------------------------------- /cypress/integration/e2e/donate.spec.js: -------------------------------------------------------------------------------- 1 | describe('Test donate button', () => { 2 | beforeEach(() => { 3 | cy.visit('/') 4 | }) 5 | 6 | it('Should redirect to projects page', () => { 7 | cy.get('button') 8 | .contains(/donate/i) 9 | .click() 10 | cy.url().should('include', 'projects') 11 | }) 12 | 13 | xit('Should open popup', () => { 14 | cy.contains(/create a project/i).should('exist') 15 | cy.contains(/create a project/i).click({ force: true }) 16 | cy.contains(/welcome to giveth/i) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "jsx": "preserve", 6 | "lib": ["dom", "es2015", "es2017"], 7 | "strict": true, 8 | "noEmit": true, 9 | "noImplicitAny": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "removeComments": false, 16 | "types": ["cypress", "@testing-library/cypress"] 17 | }, 18 | "include": ["./src/**/*"] 19 | } -------------------------------------------------------------------------------- /src/components/content/Logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import logo from '../../images/giveth-logo-blue.svg' 3 | import coTookenLogo from '../../images/logos/co2ken-logo.png' 4 | // import Img from 'gatsby-image' 5 | 6 | const Logo = props => { 7 | let siteLogo 8 | const siteId = process.env.GATSBY_SITE_ID 9 | 10 | if (siteId === 'giveth') { 11 | siteLogo = logo 12 | } else if (siteId === 'co2ken') { 13 | siteLogo = coTookenLogo 14 | } 15 | return logo 16 | } 17 | 18 | export default Logo 19 | -------------------------------------------------------------------------------- /src/components/create-project-form/inputs/index.js: -------------------------------------------------------------------------------- 1 | export { ProjectNameInput } from './ProjectNameInput' 2 | export { ProjectAdminInput } from './ProjectAdminInput' 3 | export { ProjectDescriptionInput } from './ProjectDescriptionInput' 4 | export { ProjectCategoryInput } from './ProjectCategotyInput' 5 | export { ProjectImageInput } from './ProjectImageInput' 6 | export { ProjectImpactLocationInput } from './ProjectImpactLocationInput' 7 | export { ProjectBankAccountInput } from './ProjectBankAccountInput' 8 | export { ProjectEthAddressInput } from './ProjectEthAddressInput' 9 | -------------------------------------------------------------------------------- /src/images/svg/general/dropdown-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/contextProvider/popupProvider.js: -------------------------------------------------------------------------------- 1 | import React, { createContext, useState, useContext } from 'react' 2 | 3 | export const PopupContext = createContext() 4 | 5 | export const PopupProvider = ({ children }) => { 6 | const [value, setValue] = useState() 7 | const triggerPopup = (type, extra) => setValue({ type, extra }) 8 | const clearPopup = () => setValue() 9 | 10 | return ( 11 | 12 | {children} 13 | 14 | ) 15 | } 16 | 17 | export const usePopup = () => useContext(PopupContext) 18 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APOLLO_AUTH_TOKEN= 2 | APOLLO_KEY= 3 | GATSBY_BLOCK_NATIVE_DAPP_ID= 4 | CONTENTFUL_ACCESS_TOKEN= 5 | CONTENTFUL_SPACE_ID= 6 | GATSBY_APOLLO_SERVER= 7 | GATSBY_ETHERSCAN_API_KEY= 8 | GATSBY_ETHEREUM_NODE= 9 | GATSBY_EXPERIMENTAL_ROUTING_APIS=1 10 | GATSBY_GOOGLE_MAPS_API_KEY= 11 | GATSBY_LOCAL_USER_LABEL= 12 | GATSBY_MAILCHIMP_APILINK= 13 | GATSBY_CRYPTOCOMPARE_KEY= 14 | GATSBY_NETWORK= 15 | GATSBY_NETWORK_ID= 16 | GATSBY_SITE_ID= 17 | PROJECT_SEARCH=true 18 | STRIPE_PUBLIC_KEY= 19 | TORUS_DEBUG_LOGGING=false 20 | GATSBY_PORTIS_KEY=xxxx 21 | GATSBY_OUR_SECRET= 22 | SENTRY_ID= 23 | ENVIRONMENT= 24 | -------------------------------------------------------------------------------- /src/components/global.css: -------------------------------------------------------------------------------- 1 | .pac-item { 2 | /* For Google Autocomplete container*/ 3 | cursor: pointer !important; 4 | } 5 | 6 | 7 | 8 | /* quill editor styles */ 9 | .ql-editor { 10 | font-family: 'Red Hat Text', sans-serif; 11 | } 12 | .ql-editor img{ 13 | max-width: 100%; 14 | } 15 | .ql-video-wrapper { 16 | position: relative; 17 | padding-bottom: 56.25%; 18 | height: 0; 19 | overflow: hidden; 20 | max-width: 100%; 21 | } 22 | .ql-video-wrapper iframe, .embed-container object, .embed-container embed{ 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | width: 100%; 27 | height: 100%; 28 | } -------------------------------------------------------------------------------- /siteMetaData.js: -------------------------------------------------------------------------------- 1 | const siteId = process.env.GATSBY_SITE_ID 2 | let siteMetaData 3 | 4 | if (siteId === 'giveth') { 5 | siteMetaData = { 6 | title: 'Giveth Donation Application', 7 | description: 'Building the Future of Giving #Blockchain4Good', 8 | author: '@giveth' 9 | } 10 | } else if (siteId === 'co2ken') { 11 | siteMetaData = { 12 | title: 'CO2ken tokenized carbon', 13 | description: 'Decarbonizing the Ethereum ecosystem', 14 | author: '@co2ken' 15 | } 16 | } else { 17 | throw Error('Invalid process.env.GATSBY_SITE_ID', process.env.GATSBY_SITE_ID) 18 | } 19 | module.exports = { 20 | siteMetaData 21 | } 22 | -------------------------------------------------------------------------------- /src/images/decorator-clouds.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/images/decorator-fizzy-square.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/images/decorator-fizzy-square-rotated.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/content/HeroSideImage.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | /** 3 | * Decorative images 4 | */ 5 | import React from 'react' 6 | import { jsx } from 'theme-ui' 7 | import givethHeroSide from '../../images/decorator-leaf.svg' 8 | // import co2kenHeroSide from '' 9 | 10 | const siteId = process.env.GATSBY_SITE_ID 11 | 12 | let heroSide 13 | if (siteId === 'giveth') { 14 | heroSide = givethHeroSide 15 | } else if (siteId === 'co2ken') { 16 | heroSide = givethHeroSide 17 | } 18 | const HeroSide = () => { 19 | //if (!heroSide) return null 20 | return ( 21 | 26 | ) 27 | } 28 | export default HeroSide 29 | -------------------------------------------------------------------------------- /src/components/home/MediumFeed.js: -------------------------------------------------------------------------------- 1 | import { useStaticQuery, graphql } from 'gatsby' 2 | 3 | export const useMediumFeed = () => { 4 | const mediumData = useStaticQuery(graphql` 5 | query MediumQuery { 6 | allMediumPost(limit: 2, sort: { fields: createdAt, order: DESC }) { 7 | edges { 8 | node { 9 | id 10 | createdAt 11 | title 12 | previewContent { 13 | subtitle 14 | } 15 | author { 16 | name 17 | } 18 | virtuals { 19 | readingTime 20 | } 21 | uniqueSlug 22 | } 23 | } 24 | } 25 | } 26 | `) 27 | 28 | return mediumData 29 | } 30 | -------------------------------------------------------------------------------- /cypress/integration/e2e/soft-launch-warnings.spec.js: -------------------------------------------------------------------------------- 1 | describe('Test soft launch warnings on first page', () => { 2 | beforeEach(() => { 3 | cy.visit('/') 4 | }) 5 | 6 | // it('Should open and close toast soft launch', () => { 7 | // cy.contains(/We're in Softlaunch mode/i).should('exist') 8 | // cy.contains(/We're in Softlaunch mode/i).click() 9 | // cy.contains(/We're in Softlaunch mode/i).should('not.exist') 10 | // }) 11 | 12 | it('Should open github soft launch', () => { 13 | cy.contains(/give feedback/i).should('exist') 14 | cy.contains(/give feedback/i).click() 15 | // Can't go further as Cypress does not support it: https://docs.cypress.io/guides/references/trade-offs.html#Multiple-tabs 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /cypress/integration/e2e/cookies.spec.js: -------------------------------------------------------------------------------- 1 | describe('Test cookies button', () => { 2 | beforeEach(() => { 3 | cy.restoreLocalStorage() 4 | cy.visit('/') 5 | }) 6 | 7 | afterEach(() => { 8 | cy.saveLocalStorage() 9 | }) 10 | 11 | it('Should be null first time page is visited', () => { 12 | cy.getLocalStorage('cookiesAccepted').should('equal', null) 13 | }) 14 | 15 | it('Should be true after clicking cookies button', () => { 16 | cy.get('#cookies').click() 17 | cy.getLocalStorage('cookiesAccepted').should('equal', 'true') 18 | }) 19 | 20 | it('Should be true after reloading', () => { 21 | cy.getLocalStorage('cookiesAccepted').then(cookiesAccepted => { 22 | expect(cookiesAccepted).to.equal('true') 23 | }) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /src/components/content/HeroImage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Decorative images 3 | */ 4 | import React from 'react' 5 | import givethHeroSide from '../../images/decorator-leaf.svg' 6 | // import co2kenHeroSide from '' 7 | import givethHeroMain from '../../images/people-header.svg' 8 | import co2kenHeroMain from '../../images/tree-planting.jpg' 9 | import styled from '@emotion/styled' 10 | 11 | const siteId = process.env.GATSBY_SITE_ID 12 | 13 | let heroMain 14 | if (siteId === 'giveth') { 15 | heroMain = givethHeroMain 16 | } else if (siteId === 'co2ken') { 17 | heroMain = co2kenHeroMain 18 | } 19 | const HeroImage = styled.div` 20 | width: 50vw; 21 | height: 80vh; 22 | background: url(${heroMain}); 23 | background-position: left top; 24 | background-repeat: no-repeat; 25 | ` 26 | export default HeroImage 27 | -------------------------------------------------------------------------------- /src/components/richTextViewer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const ReactQuill = React.lazy(() => import('react-quill')) 4 | 5 | function RichTextViewer({ content }) { 6 | const isSSR = typeof window === 'undefined' 7 | 8 | return ( 9 |
10 | {!isSSR && ( 11 | cy

}> 12 | 18 |
19 | )} 20 |
21 | //
25 | ) 26 | } 27 | 28 | export default RichTextViewer 29 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | // eslint-disable-next-line no-unused-vars 19 | module.exports = (on, config) => { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | } 23 | -------------------------------------------------------------------------------- /src/services/wallet.js: -------------------------------------------------------------------------------- 1 | import Web3 from 'web3' 2 | import React from 'react' 3 | import { getWallet } from '../wallets' 4 | 5 | export function isAddressENS(address) { 6 | return address.toLowerCase().indexOf('.eth') > -1 7 | } 8 | export function isWalletAddressValid(address) { 9 | if (address.length !== 42 || !Web3.utils.isAddress(address)) { 10 | return false 11 | } else { 12 | return true 13 | } 14 | } 15 | export async function getAddressFromENS(address) { 16 | const wallet = await getWallet('torus') 17 | await wallet.init() 18 | const ens = await wallet.web3.eth.ens.getOwner(address) 19 | 20 | let zeroXAddress 21 | if (ens !== '0x0000000000000000000000000000000000000000') { 22 | zeroXAddress = ens 23 | } else { 24 | zeroXAddress = address 25 | } 26 | 27 | if (isWalletAddressValid(zeroXAddress)) { 28 | return zeroXAddress 29 | } else { 30 | return new Error('Error gettingAddressFromENS') 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/utils/useComponentVisible.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useRef } from 'react' 2 | 3 | export default function useComponentVisible(initialIsVisible) { 4 | const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible) 5 | const ref = useRef(null) 6 | 7 | const handleHideDropdown = event => { 8 | if (event.key === 'Escape') { 9 | setIsComponentVisible(false) 10 | } 11 | } 12 | 13 | const handleClickOutside = event => { 14 | if (ref.current && !ref.current.contains(event.target)) { 15 | setIsComponentVisible(false) 16 | } 17 | } 18 | 19 | useEffect(() => { 20 | document.addEventListener('keydown', handleHideDropdown, true) 21 | document.addEventListener('click', handleClickOutside, true) 22 | return () => { 23 | document.removeEventListener('keydown', handleHideDropdown, true) 24 | document.removeEventListener('click', handleClickOutside, true) 25 | } 26 | }) 27 | 28 | return { ref, isComponentVisible, setIsComponentVisible } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/loadingModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Spinner } from 'theme-ui' 3 | import Modal from 'react-modal' 4 | 5 | const customStyles = { 6 | overlay: { 7 | position: 'fixed', 8 | zIndex: 4, 9 | top: 0, 10 | left: 0, 11 | right: 0, 12 | bottom: 0, 13 | backgroundColor: 'rgba(255, 255, 255, 0.25)', 14 | backdropFilter: 'blur(2px)', 15 | '-webkit-backdrop-filter': 'blur(2px)' 16 | }, 17 | content: { 18 | top: '50%', 19 | left: '50%', 20 | right: 'auto', 21 | bottom: 'auto', 22 | borderRadius: '12px', 23 | borderColor: 'transparent', 24 | marginRight: '-50%', 25 | transform: 'translate(-50%, -50%)' 26 | } 27 | } 28 | 29 | function LoadingModal(props) { 30 | return ( 31 | 37 | 38 | 39 | ) 40 | } 41 | 42 | export default LoadingModal 43 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "public" 3 | 4 | # [[plugins]] 5 | # package = "netlify-plugin-gatsby-cache" 6 | 7 | [[plugins]] 8 | # https://github.com/cypress-io/netlify-plugin-cypress 9 | package = "netlify-plugin-cypress" 10 | # We don't need to run all tests, just a few sanity specs 11 | [plugins.inputs] 12 | enable = false 13 | # let's test the local site before deploy 14 | [plugins.inputs.postBuild] 15 | enable = true 16 | spec = "cypress/integration/e2e/*.js" 17 | 18 | [build.environment] 19 | # cache Cypress binary in local "node_modules" folder so Netlify caches it 20 | CYPRESS_CACHE_FOLDER = "./node_modules/CypressBinary" 21 | # set TERM variable for terminal output 22 | TERM = "xterm" 23 | 24 | [[redirects]] 25 | from = "/donate/:id" 26 | to = "/donate" 27 | status = 200 28 | force = true 29 | 30 | [[redirects]] 31 | from = "/project/:id" 32 | to = "/project" 33 | status = 200 34 | force = true 35 | 36 | [[redirects]] 37 | from = "/user/:address" 38 | to = "/user" 39 | status = 200 40 | force = true -------------------------------------------------------------------------------- /src/images/decorator-elements.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/services/ethersSigner.js: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers' 2 | 3 | class UncheckedJsonRpcSigner extends ethers.Signer { 4 | constructor(signer) { 5 | super() 6 | ethers.utils.defineReadOnly(this, 'signer', signer) 7 | ethers.utils.defineReadOnly(this, 'provider', signer.provider) 8 | } 9 | 10 | getAddress() { 11 | return this.signer.getAddress() 12 | } 13 | 14 | sendTransaction(transaction) { 15 | return this.signer.sendUncheckedTransaction(transaction).then(hash => ({ 16 | hash, 17 | nonce: null, 18 | gasLimit: null, 19 | gasPrice: null, 20 | data: null, 21 | value: null, 22 | chainId: null, 23 | confirmations: 0, 24 | from: null, 25 | wait: confirmations => 26 | this.provider.waitForTransaction(hash, confirmations) 27 | })) 28 | } 29 | } 30 | 31 | function getSigner(provider) { 32 | try { 33 | return new ethers.providers.Web3Provider(provider.provider).getSigner() 34 | } catch (error) { 35 | console.log({ error }) 36 | } 37 | } 38 | 39 | export default getSigner 40 | -------------------------------------------------------------------------------- /src/components/modal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Modal from 'react-modal' 3 | 4 | const customStyles = { 5 | overlay: { 6 | position: 'fixed', 7 | top: 0, 8 | left: 0, 9 | right: 0, 10 | bottom: 0, 11 | zIndex: 2, 12 | backgroundColor: 'rgba(255, 255, 255, 0.05)', 13 | backdropFilter: 'blur(2px)', 14 | '-webkit-backdrop-filter': 'blur(2px)' 15 | }, 16 | content: { 17 | top: '50%', 18 | left: '50%', 19 | right: 'auto', 20 | bottom: 'auto', 21 | overflow: 'hidden', 22 | padding: 0, 23 | borderRadius: '12px', 24 | borderColor: 'transparent', 25 | marginRight: '-50%', 26 | transform: 'translate(-50%, -50%)', 27 | filter: 'drop-shadow(0px 4px 68px #DFDAE8)' 28 | } 29 | } 30 | 31 | function CustomModal(props) { 32 | return ( 33 | 39 | {props.children} 40 | 41 | ) 42 | } 43 | 44 | export default CustomModal 45 | -------------------------------------------------------------------------------- /src/components/project/firstGiveBadge.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text, Image } from 'theme-ui' 3 | import GiverBadge from '../../images/giverBadge@40x40.png' 4 | 5 | function FirstGiveBadge() { 6 | return ( 7 | 16 | 17 | 18 | 19 | 20 | 25 | Be the first to give! 26 | 27 | 28 | Your early support will go a long way and help inspire others to 29 | donate. 30 | 31 | 32 | 33 | ) 34 | } 35 | 36 | export default FirstGiveBadge 37 | -------------------------------------------------------------------------------- /src/components/image.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useStaticQuery, graphql } from 'gatsby' 3 | import Img from 'gatsby-image' 4 | 5 | /* 6 | * This component is built using `gatsby-image` to automatically serve optimized 7 | * images with lazy loading and reduced file sizes. The image is loaded using a 8 | * `useStaticQuery`, which allows us to load the image from directly within this 9 | * component, rather than having to pass the image data down from pages. 10 | * 11 | * For more information, see the docs: 12 | * - `gatsby-image`: https://gatsby.dev/gatsby-image 13 | * - `useStaticQuery`: https://www.gatsbyjs.org/docs/use-static-query/ 14 | */ 15 | 16 | const Image = () => { 17 | const data = useStaticQuery(graphql` 18 | query { 19 | placeholderImage: file(relativePath: { eq: "giveth-logo-white.png" }) { 20 | childImageSharp { 21 | fluid(maxWidth: 80) { 22 | ...GatsbyImageSharpFluid 23 | } 24 | } 25 | } 26 | } 27 | `) 28 | 29 | return ( 30 | 34 | ) 35 | } 36 | 37 | export default Image 38 | -------------------------------------------------------------------------------- /src/images/giveth-logo-blue.svg: -------------------------------------------------------------------------------- 1 | Giveth Logo icon blackAsset 3 -------------------------------------------------------------------------------- /src/images/giveth-logo-purple.svg: -------------------------------------------------------------------------------- 1 | Giveth Logo icon blackAsset 3 -------------------------------------------------------------------------------- /src/services/project.js: -------------------------------------------------------------------------------- 1 | import { client } from '../apollo/client' 2 | import { ACTIVATE_PROJECT, DEACTIVATE_PROJECT } from '../apollo/gql/projects' 3 | 4 | export async function deactivateProject(data, onSuccess) { 5 | try { 6 | const { projectId } = data 7 | const edit = await client.mutate({ 8 | mutation: DEACTIVATE_PROJECT, 9 | variables: { 10 | projectId: parseFloat(projectId) 11 | } 12 | }) 13 | if (edit?.data?.deactivateProject) { 14 | onSuccess() 15 | } 16 | } catch (error) { 17 | console.log({ error }) 18 | } 19 | } 20 | 21 | export async function toggleProjectActivation(data, isActive, onSuccess) { 22 | try { 23 | const { projectId } = data 24 | const edit = await client.mutate({ 25 | mutation: !isActive ? ACTIVATE_PROJECT : DEACTIVATE_PROJECT, 26 | variables: { 27 | projectId: parseFloat(projectId) 28 | } 29 | }) 30 | const response = !isActive 31 | ? edit?.data?.activateProject 32 | : edit?.data?.deactivateProject 33 | if (response) { 34 | onSuccess(!isActive ? 'Project Activated' : 'Project Deactivated') 35 | } 36 | return response 37 | } catch (error) { 38 | console.log({ error }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/cypress/add-commands' 2 | import 'cypress-localstorage-commands' 3 | import Web3 from 'web3' 4 | 5 | Cypress.Commands.add('setWeb3Provider', () => { 6 | cy.window().then(window => { 7 | window.ethereum = new Web3( 8 | new Web3.providers.WebsocketProvider('ws://localhost:8545') 9 | ) 10 | window.ethereum.isTest = true 11 | 12 | window.localStorage.setItem('cookiesAccepted', 'true') 13 | window.localStorage.setItem('githubIssueClosed', 'true') 14 | window.localStorage.setItem( 15 | 'giveth_user_local', 16 | JSON.stringify({ 17 | walletType: '', 18 | walletAddresses: ['0xFE3B557E8Fb62b89F4916B721be55cEb828dBd73'], 19 | activeWalletIndex: 0, 20 | avatar: null, 21 | email: 'giveth1@yopmail.com', 22 | id: '1', 23 | firstName: 'Test', 24 | lastName: 'Giveth', 25 | location: 'earth', 26 | name: 'Test Giveth', 27 | url: '', 28 | token: Cypress.env('CYPRESS_USER_LOCAL_TOKEN'), 29 | isTest: true 30 | }) 31 | ) 32 | 33 | window.localStorage.setItem( 34 | 'giveth_user_local_token', 35 | Cypress.env('CYPRESS_USER_LOCAL_TOKEN') 36 | ) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /src/images/icon-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/svg/create/projectImageGallery2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /static/assets/create/projectImageGallery2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/contextProvider/projectProvider.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | // import useLocalStorage from './useLocalStorage' 3 | 4 | const projectContext = React.createContext({}) 5 | 6 | const ProjectProvider = props => { 7 | // Use this hook to hydrate from local store. Not tested yet 8 | // const [value, setValue] = useLocalStorage('name', []) 9 | 10 | const [currentProjectView, setCurrentProjectView] = React.useState({ 11 | project: '', 12 | donations: [] 13 | }) 14 | 15 | const providerValue = React.useMemo( 16 | () => ({ 17 | currentProjectView, 18 | setCurrentProjectView 19 | }), 20 | [currentProjectView] 21 | ) 22 | 23 | return ( 24 | 25 | {props.children} 26 | 27 | ) 28 | } 29 | 30 | export const ProjectConsumer = projectContext.Consumer 31 | export const ProjectContext = projectContext 32 | export default ProjectProvider 33 | 34 | // EXAMPLE ON CONSUMER 35 | // const { value, value2 } = React.useContext(MyContext); 36 | // const [stateValue, setStateValue] = value; 37 | // const [stateValue2, setStateValue2] = value2; 38 | 39 | // based on: https://stackoverflow.com/questions/57840535/passing-multiple-value-and-setter-pairs-to-context-provider-in-react 40 | -------------------------------------------------------------------------------- /src/images/icon-share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/pages/faq.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Text, Box } from 'theme-ui' 3 | import { graphql } from 'gatsby' 4 | import React from 'react' 5 | import Seo from '../components/seo' 6 | import styled from '@emotion/styled' 7 | // import useMediaQuery from 'react-responsive' 8 | 9 | import Layout from '../components/layout' 10 | import ContentFaq from '../components/content/ContentFaq' 11 | 12 | const Main = styled(Box)`` 13 | 14 | const Faq = ({ data }) => { 15 | // const isMobile = useMediaQuery({ query: '(max-width: 825px)' }) 16 | return ( 17 | 18 | 19 |
20 | FAQ 21 | 22 |
23 |
24 | ) 25 | } 26 | 27 | export default Faq 28 | 29 | export const query = graphql` 30 | query Faq { 31 | faqA: allContentfulFaqEntry( 32 | sort: { fields: [createdAt], order: ASC } 33 | filter: { category: { category: { eq: "General" } } } 34 | ) { 35 | edges { 36 | node { 37 | id 38 | linkId 39 | createdAt 40 | question 41 | answer { 42 | json 43 | } 44 | category { 45 | id 46 | category 47 | } 48 | } 49 | } 50 | } 51 | } 52 | ` 53 | -------------------------------------------------------------------------------- /src/contextProvider/useLocalStorage.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | export default function useLocalStorage(key, initialValue) { 4 | // State to store our value 5 | // Pass initial state function to useState so logic is only executed once 6 | const [storedValue, setStoredValue] = useState(() => { 7 | try { 8 | // Get from local storage by key 9 | const item = window.localStorage.getItem(key) 10 | // Parse stored json or if none return initialValue 11 | return item ? JSON.parse(item) : initialValue 12 | } catch (error) { 13 | // If error also return initialValue 14 | console.log(error) 15 | return initialValue 16 | } 17 | }) 18 | 19 | // Return a wrapped version of useState's setter function that ... 20 | // ... persists the new value to localStorage. 21 | const setValue = value => { 22 | try { 23 | // Allow value to be a function so we have same API as useState 24 | const valueToStore = 25 | value instanceof Function ? value(storedValue) : value 26 | // Save state 27 | setStoredValue(valueToStore) 28 | // Save to local storage 29 | window.localStorage.setItem(key, JSON.stringify(valueToStore)) 30 | } catch (error) { 31 | // A more advanced implementation would handle the error case 32 | console.log(error) 33 | } 34 | } 35 | 36 | return [storedValue, setValue] 37 | } 38 | -------------------------------------------------------------------------------- /src/images/svg/general/search-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/templates/project.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import React from 'react' 3 | import { Flex, Text, jsx } from 'theme-ui' 4 | import Seo from '../components/seo' 5 | import Layout from '../components/layout' 6 | import { ProjectDonatorView } from '../components/project' 7 | import { useWallet } from '../contextProvider/WalletProvider' 8 | 9 | const ShowComponents = ({ pageContext }) => { 10 | const { user } = useWallet() 11 | const statusId = pageContext?.project?.status?.id 12 | const isAdmin = statusId === user?.id 13 | return ( 14 | <> 15 | {/* {statusId && statusId !== '5' && !isAdmin ? ( 16 | 17 | 18 | Project Not Available 19 | 20 | 21 | ) : ( */} 22 | 23 | {/* )} */} 24 | 25 | ) 26 | } 27 | 28 | const Project = ({ pageContext }) => { 29 | return ( 30 | 31 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default Project 45 | -------------------------------------------------------------------------------- /src/components/donateForm.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Label, Input, Button } from 'theme-ui' 3 | import { useForm } from 'react-hook-form' 4 | import styled from '@emotion/styled' 5 | import BigNumber from 'bignumber.js' 6 | 7 | import theme from '../gatsby-plugin-theme-ui/index' 8 | 9 | const DonationForm = styled.form` 10 | display: grid; 11 | grid-gap: 0.5rem; 12 | grid-template-columns: 0px auto auto; 13 | align-items: bottom; 14 | padding: 0.2rem 0px; 15 | .donatebutton { 16 | align-self: start; 17 | height: 36px; 18 | background-color: ${theme.colors.primary}; 19 | } 20 | ` 21 | 22 | const Donate = props => { 23 | const { handleSubmit, register } = useForm() 24 | const { doDonate } = props 25 | const onSubmit = values => { 26 | doDonate(values) 27 | } 28 | 29 | const maxAmount = new BigNumber(props.maxAmount || 0) 30 | 31 | return ( 32 | 37 | 52 | ) 53 | } 54 | export default Donate 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env.development 56 | .env.production 57 | .env* 58 | 59 | # gatsby files 60 | .cache/ 61 | public/ 62 | 63 | # Mac files 64 | .DS_Store 65 | 66 | # Yarn 67 | yarn-error.log 68 | .pnp/ 69 | .pnp.js 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # IDE 75 | .idea 76 | 77 | #Dolphin directory listing 78 | .directory 79 | 80 | # Local Netlify folder 81 | .netlify 82 | 83 | # Cypress 84 | cypress.env.json 85 | cypress/screenshots 86 | cypress/videos 87 | -------------------------------------------------------------------------------- /src/content/giveth.md: -------------------------------------------------------------------------------- 1 | --- 2 | # meta 3 | slug: 'giveth-home' 4 | 5 | # herosection 6 | mainHead: 'Welcome to the' 7 | headBold: 'future of giving' 8 | mainText: 'Donate directly to social good projects with zero added fees.' 9 | mainButton: 'DONATE' 10 | mainButtonText: 'Start raising funds for your project' 11 | 12 | # infosection 13 | infoHead: 'What is Giveth' 14 | infoSubtitle: ' A Decentralized Altruistic Community using blockchain technology to make the world a better place.' 15 | infoButtonText: 'Read our story on the future of giving' 16 | feature1: 'Altruistic' 17 | feature1Text: 'We build tools for the common good and support others in doing so as well. On the Giveth DApp, 100% of the funds donated go to the cause the donor intended to support.' 18 | feature2: 'Decentralized' 19 | feature2Text: 'We are an open, non-hierarchical global initiative - We empower communities with novel decentralized technologies to address their collective needs.' 20 | feature3: 'Community' 21 | feature3Text: 'We build tools that create strong bonds and alignment for people and the planet. We see donations as an opportunity to connect Givers to the people on the ground doing the good work.' 22 | featureCta: 'JOIN THE FUTURE OF GIVING' 23 | infoHead2: 'How it works' 24 | infoSubtitle2: 'Our system connects the people on the ground directly to the Givers, and provides a level of transparency and accountability no other platform can offer.' 25 | userType1Title: 'For Makers' 26 | userType1Cta: 'CREATE A PROJECT' 27 | userType2Title: 'For Givers' 28 | userType2Cta: 'DONATE TO A PROJECT' 29 | --- 30 | -------------------------------------------------------------------------------- /src/templates/donate.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { Flex, Text, Grid, jsx } from 'theme-ui' 3 | import styled from '@emotion/styled' 4 | import Seo from '../components/seo' 5 | import Layout from '../components/layout' 6 | import DonationView from '../components/donate' 7 | 8 | const Content = styled(Grid)` 9 | display: flex; 10 | flex-direction: row; 11 | @media (max-width: 800px) { 12 | flex-direction: column-reverse; 13 | } 14 | ` 15 | 16 | const ShowComponents = props => { 17 | const { pageContext } = props 18 | const projectStatus = pageContext?.project?.status 19 | 20 | return ( 21 | 22 | {/* {projectStatus && projectStatus?.id !== '5' ? ( 23 | 24 | 25 | Project Not Available 26 | 27 | 28 | ) : ( */} 29 | 30 | {/* )} */} 31 | 32 | ) 33 | } 34 | 35 | const Donate = props => { 36 | const { pageContext } = props 37 | return ( 38 | 39 | 47 | 48 | 49 | ) 50 | } 51 | 52 | export default Donate 53 | -------------------------------------------------------------------------------- /src/components/animations/confetti/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Lottie from 'react-lottie' 3 | import animationData from './animation.json' 4 | 5 | export default class LottieControl extends React.Component { 6 | constructor(props) { 7 | super(props) 8 | this.state = { isStopped: false, isPaused: false } 9 | } 10 | 11 | render() { 12 | const buttonStyle = { 13 | display: 'block', 14 | margin: '10px auto' 15 | } 16 | 17 | const defaultOptions = { 18 | loop: true, 19 | autoplay: true, 20 | animationData: animationData, 21 | rendererSettings: { 22 | preserveAspectRatio: 'xMidYMid slice' 23 | } 24 | } 25 | 26 | return ( 27 |
28 | 36 | {/* 42 | 48 | */} 54 |
55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/components/animations/subscribed/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Lottie from 'react-lottie' 3 | import animationData from './animation.json' 4 | 5 | export default class LottieControl extends React.Component { 6 | constructor(props) { 7 | super(props) 8 | this.state = { isStopped: false, isPaused: false } 9 | } 10 | 11 | render() { 12 | const buttonStyle = { 13 | display: 'block', 14 | margin: '10px auto' 15 | } 16 | 17 | const defaultOptions = { 18 | loop: true, 19 | autoplay: true, 20 | animationData: animationData, 21 | rendererSettings: { 22 | preserveAspectRatio: 'xMidYMid slice' 23 | } 24 | } 25 | 26 | return ( 27 |
28 | 36 | {/* 42 | 48 | */} 54 |
55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pages/join.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Flex, Grid } from 'theme-ui' 3 | import { graphql } from 'gatsby' 4 | 5 | import Layout from '../components/layout' 6 | import Seo from '../components/seo' 7 | import Hero from '../components/content/JoinPageHero' 8 | import JoinChatCard from '../components/content/JoinPageCard' 9 | 10 | const JoinPage = ({ data }) => { 11 | return ( 12 | 13 | 14 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | ) 27 | } 28 | 29 | export default JoinPage 30 | 31 | export const query = graphql` 32 | query JoinChatQuery { 33 | contentChats: allContentfulContentJoinChatprovider( 34 | sort: { order: ASC, fields: createdAt } 35 | ) { 36 | edges { 37 | node { 38 | id 39 | platformTitle 40 | descriptionText 41 | onboardingLink 42 | platformLogo { 43 | id 44 | file { 45 | url 46 | fileName 47 | contentType 48 | } 49 | } 50 | cardBackgroundImage { 51 | id 52 | file { 53 | url 54 | fileName 55 | contentType 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | ` 63 | -------------------------------------------------------------------------------- /src/components/create-project-form/modals/LocationInputModal.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { Link } from 'gatsby' 3 | import { Button, Flex, Text, Input } from 'theme-ui' 4 | 5 | export const LocationInputModal = ({ 6 | showModal, 7 | setShowModal, 8 | setLocation 9 | }) => { 10 | useEffect(() => { 11 | console.log('change') 12 | }) 13 | return ( 14 |
28 | 45 |
46 | setLocation(e.target.value)} 52 | /> 53 |
54 |
55 |
56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /src/services/auth.js: -------------------------------------------------------------------------------- 1 | export const isBrowser = () => typeof window !== 'undefined' 2 | 3 | export const getUser = () => 4 | isBrowser() && window.localStorage.getItem(getLocalStorageUserLabel()) 5 | ? JSON.parse(window.localStorage.getItem(getLocalStorageUserLabel())) 6 | : {} 7 | 8 | export function setUser (user) { 9 | return window.localStorage.setItem( 10 | getLocalStorageUserLabel(), 11 | JSON.stringify(user) 12 | ) 13 | } 14 | 15 | export function handleLogout () { 16 | logout() 17 | } 18 | 19 | export const checkIfLoggedIn = () => { 20 | const user = getUser() 21 | 22 | return !!user.walletAddresses 23 | } 24 | 25 | export const logout = (callback = () => {}) => { 26 | if (isBrowser()) { 27 | window.localStorage.removeItem(getLocalStorageUserLabel()) 28 | window.localStorage.removeItem(getLocalStorageTokenLabel()) 29 | window.localStorage.removeItem('create-form') 30 | // TODO: let's check if we should remove everything or just be careful 31 | // window.localStorage.clear() 32 | } 33 | callback() 34 | } 35 | 36 | export function getLocalStorageUserLabel () { 37 | const gatsbyUser = process.env.GATSBY_LOCAL_USER_LABEL 38 | ? process.env.GATSBY_LOCAL_USER_LABEL + '_' + process.env.ENVIRONMENT 39 | : 'gatsbyUser' + '_' + process.env.ENVIRONMENT 40 | 41 | return gatsbyUser 42 | } 43 | 44 | export function getLocalStorageTokenLabel () { 45 | const tokenLabel = getLocalStorageUserLabel() + '_token' 46 | 47 | return tokenLabel 48 | } 49 | 50 | export function getUserToken () { 51 | const userToken = window.localStorage.getItem(getLocalStorageTokenLabel()) 52 | return userToken || '' 53 | } 54 | -------------------------------------------------------------------------------- /src/components/create-project-form/utils.js: -------------------------------------------------------------------------------- 1 | import { GET_PROJECT_BY_ADDRESS } from '../../apollo/gql/projects' 2 | import { client } from '../../apollo/client' 3 | import { 4 | getAddressFromENS, 5 | isWalletAddressValid, 6 | isAddressENS 7 | } from '../../services/wallet' 8 | import { ethers } from 'ethers' 9 | 10 | const infuraId = process.env.GATSBY_INFURA_ID 11 | const network = process.env.GATSBY_NETWORK 12 | const provider = new ethers.providers.InfuraProvider(network, infuraId) 13 | 14 | export async function getProjectWallet (projectWalletAddress) { 15 | if (projectWalletAddress) { 16 | try { 17 | const isENS = await isAddressENS(projectWalletAddress) 18 | if (!isWalletAddressValid(projectWalletAddress) && !isENS) { 19 | throw new Error('Wallet address is invalid') 20 | } 21 | 22 | projectWalletAddress = isENS 23 | ? await getAddressFromENS(projectWalletAddress) 24 | : projectWalletAddress 25 | } catch (error) { 26 | console.log({ error }) 27 | throw new Error(`Error while validating wallet - ${projectWalletAddress}`) 28 | } 29 | } 30 | return projectWalletAddress 31 | } 32 | 33 | export async function projectWalletAlreadyUsed (projectWalletAddress) { 34 | const res = await client.query({ 35 | query: GET_PROJECT_BY_ADDRESS, 36 | variables: { 37 | address: projectWalletAddress 38 | } 39 | }) 40 | if (res?.data?.projectByAddress) { 41 | return true 42 | } 43 | return false 44 | } 45 | 46 | export async function isSmartContract (projectWalletAddress) { 47 | const code = await provider.getCode(projectWalletAddress) 48 | 49 | return code !== '0x' 50 | } 51 | -------------------------------------------------------------------------------- /src/apollo/client.js: -------------------------------------------------------------------------------- 1 | import { ApolloClient, InMemoryCache } from '@apollo/client' 2 | import { createUploadLink } from 'apollo-upload-client' 3 | import { setContext } from '@apollo/client/link/context' 4 | import fetch from 'isomorphic-fetch' 5 | import gql from 'graphql-tag' 6 | import { 7 | getLocalStorageUserLabel, 8 | getLocalStorageTokenLabel 9 | } from '../services/auth' 10 | 11 | const gatsbyUser = getLocalStorageUserLabel() 12 | 13 | const httpLink = createUploadLink({ uri: process.env.GATSBY_APOLLO_SERVER }) 14 | 15 | const authLink = setContext((_, { headers }) => { 16 | // get the authentication token from local storage if it exists 17 | const token = localStorage.getItem(getLocalStorageTokenLabel()) 18 | 19 | // return the headers to the context so httpLink can read them 20 | const mutation = { 21 | authorization: token ? `Bearer ${token}` : '' 22 | } 23 | if (localStorage.getItem(gatsbyUser)) { 24 | const user = JSON.parse(localStorage.getItem(gatsbyUser)) 25 | const userAddress = user?.addresses && user.addresses[0] 26 | 27 | if (userAddress) mutation['wallet-address'] = userAddress 28 | } 29 | 30 | return { 31 | headers: { 32 | ...headers, 33 | ...mutation 34 | } 35 | } 36 | }) 37 | 38 | export const client = new ApolloClient({ 39 | cache: new InMemoryCache(), 40 | link: authLink.concat(httpLink), 41 | typeDefs: gql` 42 | enum OrderField { 43 | CreationDate 44 | Balance 45 | } 46 | 47 | enum OrderDirection { 48 | ASC 49 | DESC 50 | } 51 | 52 | type OrderBy { 53 | field: OrderField! 54 | direction: OrderDirection! 55 | } 56 | `, 57 | fetch 58 | }) 59 | -------------------------------------------------------------------------------- /src/utils/constants.js: -------------------------------------------------------------------------------- 1 | export const categoryList = [ 2 | { name: 'community', value: 'Community', source: 'adhoc' }, 3 | { name: 'food', value: 'Food', source: 'adhoc' }, 4 | { name: 'non-profit', value: 'Non-profit', source: 'adhoc' }, 5 | { name: 'housing', value: 'Housing', source: 'adhoc' }, 6 | { name: 'technology', value: 'Technology', source: 'adhoc' }, 7 | { name: 'research', value: 'Research', source: 'adhoc' }, 8 | { name: 'nutrition', value: 'Nutrition', source: 'adhoc' }, 9 | { name: 'art-culture', value: 'Art & Culture', source: 'adhoc' }, 10 | 11 | { name: 'agriculture', value: 'Agriculture', source: 'IRIS' }, 12 | { name: 'air', value: 'Air', source: 'IRIS' }, 13 | { name: 'biodiversity', value: 'Biodiversity', source: 'IRIS' }, 14 | { name: 'climate', value: 'Climate', source: 'IRIS' }, 15 | { name: 'inclusion', value: 'Inclusion', source: 'IRIS' }, 16 | { name: 'education', value: 'Education', source: 'IRIS' }, 17 | { name: 'employment', value: 'Employment', source: 'IRIS' }, 18 | { name: 'energy', value: 'Energy', source: 'IRIS' }, 19 | { name: 'finance', value: 'Finance', source: 'IRIS' }, 20 | { name: 'health', value: 'Health', source: 'IRIS' }, 21 | { name: 'infrastructure', value: 'Infrastructure', source: 'IRIS' }, 22 | { name: 'land', value: 'Land', source: 'IRIS' }, 23 | { name: 'oceans', value: 'Oceans', source: 'IRIS' }, 24 | { name: 'pollution', value: 'Pollution', source: 'IRIS' }, 25 | { name: 'real-estate', value: 'Real Estate', source: 'IRIS' }, 26 | { name: 'waste', value: 'Waste', source: 'IRIS' }, 27 | { name: 'water', value: 'Water', source: 'IRIS' }, 28 | { name: 'other', value: 'Other', source: 'adhoc' } 29 | ] 30 | -------------------------------------------------------------------------------- /src/components/user/profileView.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text, Button } from 'theme-ui' 3 | import { ProfileHeader, UserDonations, UserProjects } from './index' 4 | import { useQueryParams, StringParam } from 'use-query-params' 5 | 6 | export const PublicProfileView = props => { 7 | const [query, setQuery] = useQueryParams({ 8 | tab: StringParam 9 | }) 10 | 11 | const Tab = ({ name }) => { 12 | const tab = query?.tab?.toLowerCase() || 'projects' 13 | return ( 14 | 35 | ) 36 | } 37 | 38 | const showTab = () => { 39 | switch (query?.tab?.toLowerCase()) { 40 | case 'projects': 41 | return 42 | case 'donations': 43 | return 44 | default: 45 | return 46 | } 47 | } 48 | 49 | return ( 50 | 51 | 52 | 53 | 54 | 55 | 56 | {showTab()} 57 | 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /src/images/svg/create/projectImageGallery3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/assets/create/projectImageGallery3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/project/cancelledModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text } from 'theme-ui' 3 | import Modal from 'react-modal' 4 | import { Link } from 'gatsby' 5 | 6 | const customStyles = { 7 | overlay: { 8 | position: 'fixed', 9 | zIndex: 4, 10 | top: 0, 11 | left: 0, 12 | right: 0, 13 | bottom: 0, 14 | backgroundColor: 'rgba(255, 235, 255, 0.25)', 15 | backdropFilter: 'blur(2px)', 16 | '-webkit-backdrop-filter': 'blur(2px)' 17 | }, 18 | content: { 19 | top: '50%', 20 | left: '50%', 21 | right: 'auto', 22 | bottom: 'auto', 23 | borderRadius: '12px', 24 | borderColor: 'transparent', 25 | marginRight: '-50%', 26 | transform: 'translate(-50%, -50%)' 27 | } 28 | } 29 | 30 | function CancelledModal(props) { 31 | return ( 32 | 38 | 39 | 40 | This project is currently cancelled... 41 | 42 | 43 | 44 | Check out these other{' '} 45 | 49 | 54 | projects! 55 | 56 | 57 | 58 | 59 | 60 | ) 61 | } 62 | 63 | export default CancelledModal 64 | -------------------------------------------------------------------------------- /src/services/donation.ts: -------------------------------------------------------------------------------- 1 | import Logger from '../Logger' 2 | import { SAVE_DONATION, SAVE_DONATION_TRANSACTION } from '../apollo/gql/donations' 3 | import { client } from '../apollo/client' 4 | 5 | export async function saveDonation ( 6 | fromAddress: string, 7 | toAddress: string, 8 | transactionId: string, 9 | transactionNetworkId: number, 10 | amount: number, 11 | token: string, 12 | projectId: number 13 | ) { 14 | const saveDonationErrors = [] 15 | let donationId: any = 0 16 | try { 17 | const { data } = await client.mutate({ 18 | mutation: SAVE_DONATION, 19 | variables: { 20 | chainId: transactionNetworkId, 21 | fromAddress, 22 | toAddress, 23 | transactionId, 24 | transactionNetworkId, 25 | amount, 26 | token, 27 | projectId 28 | } 29 | }) 30 | const { saveDonation: saveDonationId } = data 31 | donationId = saveDonationId 32 | } catch (error) { 33 | saveDonationErrors.push(error) 34 | } 35 | return { 36 | donationId, 37 | saveDonationErrors, 38 | savedDonation: saveDonationErrors.length === 0 39 | } 40 | } 41 | 42 | export async function saveDonationTransaction (hash: string, donationId: Number) { 43 | const saveDonationTransactionErrors = [] 44 | let savedDonationTransaction: any = 0 45 | try { 46 | const { data, error } = await client.mutate({ 47 | mutation: SAVE_DONATION_TRANSACTION, 48 | variables: { 49 | transactionId: hash?.toString(), 50 | donationId 51 | // anonymous: false 52 | } 53 | }) 54 | savedDonationTransaction = data 55 | } catch (error) { 56 | saveDonationTransactionErrors.push(error) 57 | } 58 | 59 | return { 60 | savedDonationTransaction, 61 | saveDonationTransactionErrors 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/components/copyToClipboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text } from 'theme-ui' 3 | import theme from '../gatsby-plugin-theme-ui' 4 | import { FiCopy } from 'react-icons/fi' 5 | 6 | const CopyToClipboard = ({ text, size = '18px', children }) => { 7 | const [quickMsg, setQuickMsg] = React.useState(false) 8 | 9 | const copyEvent = () => { 10 | setQuickMsg(true) 11 | navigator.clipboard.writeText(text) 12 | setTimeout(() => setQuickMsg(false), 3000) 13 | } 14 | 15 | if (children) { 16 | return ( 17 | 21 | {quickMsg && ( 22 | 31 | 32 | copied! 33 | 34 | 35 | )} 36 | {children} 37 | 38 | ) 39 | } 40 | 41 | return ( 42 | 43 | {quickMsg && ( 44 | 52 | 53 | copied! 54 | 55 | 56 | )} 57 | 63 | 64 | ) 65 | } 66 | 67 | export default CopyToClipboard 68 | -------------------------------------------------------------------------------- /src/services/token.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from 'react' 2 | import * as Auth from '../services/auth' 3 | import { client } from '../apollo/client' 4 | import { DO_LOGIN, VALIDATE_TOKEN } from '../apollo/gql/auth' 5 | import Web3 from 'web3' 6 | import Logger from '../Logger' 7 | /** 8 | * Ok the user has a token, but is it still valid? 9 | * @param {} user 10 | * @param {*} signedMessage 11 | */ 12 | export async function validateAuthToken(token) { 13 | try { 14 | const { data } = await client.mutate({ 15 | mutation: VALIDATE_TOKEN, 16 | variables: { 17 | token 18 | } 19 | }) 20 | 21 | const isValid = data.validateToken 22 | return isValid 23 | } catch (error) { 24 | console.error('Error in token login', error) 25 | Logger.captureException(error) 26 | } 27 | } 28 | 29 | export async function getToken(user, signedMessage, isXDAI) { 30 | if (signedMessage) { 31 | try { 32 | const { data } = await client.mutate({ 33 | mutation: DO_LOGIN, 34 | variables: { 35 | walletAddress: Web3.utils.toChecksumAddress(user?.getWalletAddress()), 36 | signature: signedMessage, 37 | email: user?.email, 38 | avatar: user?.avatar, 39 | name: user?.name, 40 | hostname: window.location.hostname, 41 | isXDAI: isXDAI 42 | } 43 | }) 44 | 45 | const token = data?.loginWallet?.token 46 | const userIDFromDB = data?.loginWallet?.user?.id 47 | if (!userIDFromDB) throw new Error('No userId returned from the database') 48 | return { 49 | userIDFromDB, 50 | dbUser: data?.loginWallet?.user, 51 | token 52 | } 53 | } catch (error) { 54 | console.log('Error in token login', error) 55 | Logger.captureException(error) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/components/user/userProjects.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text, Flex, Box, Link, Button, Grid } from 'theme-ui' 3 | import ProjectCard from '../../components/projectCard' 4 | 5 | export const UserProjects = props => { 6 | const { projects } = props 7 | 8 | const Empty = ({ name }) => { 9 | return ( 10 | 18 | 19 | {name || 'This user'} hasn't created a project yet 20 | 21 | 22 | Don't stop here! There are other projects you can donate to. 23 | 24 | 25 | 28 | 29 | 30 | ) 31 | } 32 | 33 | return ( 34 | 43 | {projects?.length > 0 ? ( 44 | 53 | {projects 54 | ?.slice() 55 | .sort((a, b) => new Date(a.creationDate) - new Date(b.creationDate)) 56 | .map((project, index) => ( 57 | 58 | ))} 59 | 60 | ) : ( 61 | 62 | )} 63 | 64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /giveth2-positonic-full-stack.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": { 3 | "recommendations": [ 4 | //Prettier is needed to conveniently format on save 5 | "esbenp.prettier-vscode", 6 | //And even better correctly lint everything according to standardJS 7 | "numso.prettier-standard-vscode", 8 | //To see our status with StandardJS we can use problem highlighting - in hindsight, properly configured this could be all we need 9 | "chenxsan.vscode-standardjs", 10 | //to get SVG previews 11 | "simonsiefke.svg-preview", 12 | ] 13 | }, 14 | "folders": [ 15 | { 16 | "path": "." 17 | }, 18 | { 19 | "path": "../impact-graph" 20 | } 21 | ], 22 | "settings": { 23 | // Differentiate our giveth2 workspace from other open VSCode windows 24 | "workbench.colorCustomizations": { 25 | "titleBar.activeBackground": "#5144c2" 26 | }, 27 | // "workbench.colorCustomizations": { 28 | // "statusBar.background": "#c2449f", 29 | // "statusBarItem.hoverBackground": "#cf6ab3", 30 | // "titleBar.activeBackground": "#c2449f", 31 | // "titleBar.inactiveBackground": "#c2449f99", 32 | // "statusBar.foreground": "#e7e7e7", 33 | // "titleBar.activeForeground": "#e7e7e7", 34 | // "titleBar.inactiveForeground": "#e7e7e799", 35 | // "activityBar.activeBackground": "#cf6ab3", 36 | // "activityBar.activeBorder": "#4e601f", 37 | // "activityBar.background": "#cf6ab3", 38 | // "activityBar.foreground": "#15202b", 39 | // "activityBar.inactiveForeground": "#15202b99", 40 | // "activityBarBadge.background": "#4e601f", 41 | // "activityBarBadge.foreground": "#e7e7e7" 42 | // }, 43 | "peacock.color": "#C2449F", 44 | "editor.multiCursorModifier": "ctrlCmd", 45 | "editor.tabCompletion": "on", 46 | "editor.snippetSuggestions": "top", 47 | "editor.action.goToTypeDefinition": "on" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/images/icon-user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/pages/donate.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import React from 'react' 3 | import { Grid, Flex, Spinner, Text, jsx } from 'theme-ui' 4 | import styled from '@emotion/styled' 5 | import Seo from '../components/seo' 6 | import { useQuery } from '@apollo/client' 7 | import Layout from '../components/layout' 8 | import DonationIndex from '../components/donate' 9 | import { FETCH_PROJECT_BY_SLUG } from '../apollo/gql/projects' 10 | 11 | const Content = styled(Grid)` 12 | display: flex; 13 | flex-direction: row; 14 | @media (max-width: 800px) { 15 | flex-direction: column-reverse; 16 | } 17 | ` 18 | const ProjectNotFound = () => { 19 | return Project Not Found 20 | } 21 | 22 | const Donate = props => { 23 | const { id } = props 24 | const { loading, error, data } = useQuery(FETCH_PROJECT_BY_SLUG, { 25 | variables: { slug: id } 26 | }) 27 | 28 | return ( 29 | 30 | 38 | 39 | {error ? ( 40 | Error 41 | ) : loading ? ( 42 | 43 | ) : data?.projectBySlug?.status && 44 | data?.projectBySlug?.status?.id !== '5' ? ( 45 | 46 | 47 | Project Not Available 48 | 49 | 50 | ) : data?.projectBySlug ? ( 51 | 52 | ) : ( 53 | 54 | )} 55 | 56 | 57 | ) 58 | } 59 | 60 | export default Donate 61 | -------------------------------------------------------------------------------- /src/components/home/HomeTopProjects.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | 3 | import { jsx } from 'theme-ui' 4 | import { useApolloClient } from '@apollo/client' 5 | import { FETCH_ALL_PROJECTS } from '../../apollo/gql/projects' 6 | import { navigate } from 'gatsby' 7 | import ProjectsList, { OrderByDirection, OrderByField } from '../ProjectsList' 8 | import { useState, useEffect } from 'react' 9 | 10 | const HomeTopProjects = props => { 11 | const { projects = [], categories, fromHomePage } = props 12 | const client = useApolloClient() 13 | const [showProjects, setShowProjects] = useState(projects) 14 | const [orderByField, setOrderByField] = useState(OrderByField.Balance) 15 | const [limit, setLimit] = useState(12) 16 | // const orderBy = { 17 | // field: orderByField, 18 | // direction: OrderByDirection.DESC 19 | // } 20 | 21 | useEffect(() => { 22 | const checkProjectsAfterSSR = async () => { 23 | try { 24 | // This updates the projects after showing the SSR 25 | const { data } = await client.query({ 26 | query: FETCH_ALL_PROJECTS, 27 | // variables: { limit: 3 }, 28 | fetchPolicy: 'network-only' 29 | }) 30 | const { projects } = data || {} 31 | setShowProjects( 32 | Array.from(projects) 33 | .filter(i => i?.status?.id === '5') 34 | .sort((a, b) => b?.qualityScore > a?.qualityScore) 35 | ?.slice(0, 3) 36 | ) 37 | } catch (error) { 38 | console.log({ error }) 39 | } 40 | } 41 | checkProjectsAfterSSR() 42 | }, []) 43 | 44 | return ( 45 | navigate('/projects')} 51 | hasMore 52 | selectOrderByField={orderByField => { 53 | setLimit(2) 54 | setOrderByField(orderByField) 55 | }} 56 | /> 57 | ) 58 | } 59 | 60 | export default HomeTopProjects 61 | -------------------------------------------------------------------------------- /src/components/torus/loginButton.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { useWallet } from '../../contextProvider/WalletProvider' 3 | import { Text, Button, jsx } from 'theme-ui' 4 | import { wallets } from '../../wallets' 5 | import LoginModal from './loginModal' 6 | import { useState } from 'react' 7 | 8 | const LoginButton = props => { 9 | const [showOptions, setShowOptions] = useState(false) 10 | const [isComponentVisible, setIsComponentVisible] = useState(false) 11 | 12 | // const { 13 | // ref, 14 | // isComponentVisible, 15 | // setIsComponentVisible 16 | // } = useComponentVisible(false) 17 | const { login, ethEnabled } = useWallet() 18 | return ( 19 |
20 | 32 | { 33 | // 34 | // Object.keys(wallets).map((walletProvider, index) => { 35 | // return ( 36 | // login({ walletProvider })} 47 | // > 48 | // {walletProvider} 49 | // 50 | // ) 51 | // }) 52 | // 53 | } 54 | {isComponentVisible && wallets ? ( 55 | setIsComponentVisible(false)} 57 | isOpen={isComponentVisible} 58 | /> 59 | ) : null} 60 |
61 | ) 62 | } 63 | 64 | export default LoginButton 65 | -------------------------------------------------------------------------------- /src/components/dialog.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Container, NavLink, Text } from 'theme-ui' 3 | import styled from '@emotion/styled' 4 | import theme from '../gatsby-plugin-theme-ui/index' 5 | 6 | import LeftArrow from '../images/svg/general/left-arrow.svg' 7 | import Confetti from '../images/svg/donation/confetti.svg' 8 | 9 | import decoratorClouds from '../images/decorator-clouds.svg' 10 | 11 | const Main = styled.main` 12 | padding: 4.063rem 4.5rem 0 4.5rem; 13 | display: flex; 14 | justify-content: center; 15 | ` 16 | 17 | const DialogContainer = styled(Container)` 18 | min-height: 100vh; 19 | ` 20 | 21 | const Clouds = styled.img` 22 | position: absolute; 23 | right: 0; 24 | ` 25 | const LeftConfetti = styled(Confetti)` 26 | position: absolute; 27 | left: 3.875rem; 28 | top: 8.875rem; 29 | @media (max-width: 1100px) { 30 | left: auto; 31 | top: 9rem; 32 | right: 0.99rem; 33 | } 34 | ` 35 | 36 | const BackButton = styled(NavLink)` 37 | && { 38 | display: flex; 39 | } 40 | width: 100%; 41 | max-width: 7rem; 42 | position: absolute; 43 | left: 4.875rem; 44 | top: 4.875rem; 45 | @media (max-width: 600px) { 46 | left: 2rem; 47 | } 48 | ` 49 | 50 | const DialogContent = styled.div` 51 | margin: 3.813rem 0 0 0; 52 | ` 53 | 54 | export default function Dialog ({ children }) { 55 | return ( 56 | 57 | 58 | 59 | 60 | 61 | 70 | Giveth 71 | 72 | 73 |
74 | {children} 75 |
76 |
77 | ) 78 | } 79 | -------------------------------------------------------------------------------- /giveth2-full-stack.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": { 3 | "recommendations": [ 4 | //Prettier is needed to conveniently format on save 5 | "esbenp.prettier-vscode", 6 | //And even better correctly lint everything according to standardJS 7 | "numso.prettier-standard-vscode", 8 | //To see our status with StandardJS we can use problem highlighting - in hindsight, properly configured this could be all we need 9 | "chenxsan.vscode-standardjs", 10 | //to get SVG previews 11 | "simonsiefke.svg-preview" 12 | ] 13 | }, 14 | "folders": [ 15 | { 16 | "path": "." 17 | }, 18 | { 19 | "path": "../impact-graph" 20 | } 21 | ], 22 | "settings": { 23 | // Differentiate our giveth2 workspace from other open VSCode windows 24 | "workbench.colorCustomizations": { 25 | "titleBar.activeBackground": "#c2449f", 26 | "statusBar.background": "#c2449f", 27 | "statusBar.foreground": "#e7e7e7", 28 | "statusBarItem.hoverBackground": "#cf6ab3", 29 | "titleBar.activeForeground": "#e7e7e7", 30 | "titleBar.inactiveBackground": "#c2449f99", 31 | "titleBar.inactiveForeground": "#e7e7e799" 32 | }, 33 | // "workbench.colorCustomizations": { 34 | // "statusBar.background": "#c2449f", 35 | // "statusBarItem.hoverBackground": "#cf6ab3", 36 | // "titleBar.activeBackground": "#c2449f", 37 | // "titleBar.inactiveBackground": "#c2449f99", 38 | // "statusBar.foreground": "#e7e7e7", 39 | // "titleBar.activeForeground": "#e7e7e7", 40 | // "titleBar.inactiveForeground": "#e7e7e799", 41 | // "activityBar.activeBackground": "#cf6ab3", 42 | // "activityBar.activeBorder": "#4e601f", 43 | // "activityBar.background": "#cf6ab3", 44 | // "activityBar.foreground": "#15202b", 45 | // "activityBar.inactiveForeground": "#15202b99", 46 | // "activityBarBadge.background": "#4e601f", 47 | // "activityBarBadge.foreground": "#e7e7e7" 48 | // }, 49 | "peacock.color": "#C2449F" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/pages/my-account/projects.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Text, Flex, Box } from 'theme-ui' 3 | import React from 'react' 4 | import AccountTop from '../../components/account/AccountTop' 5 | import AccountNav from '../../components/account/AccountNavSimple' 6 | import AccountBody from '../../components/account/AccountBody' 7 | import Layout from '../../components/layout' 8 | import MyProjects from '../../components/account/myProjects' 9 | import { FETCH_USER_PROJECTS } from '../../apollo/gql/projects' 10 | import { useWallet } from '../../contextProvider/WalletProvider' 11 | import { useQuery } from '@apollo/client' 12 | 13 | const ProjectListing = props => { 14 | const { user, isLoggedIn } = useWallet() 15 | // console.log(`user in ProjectListing : ${JSON.stringify(user, null, 2)}`) 16 | console.log(`user in ProjectListing :`) 17 | 18 | //Render 19 | // const { data: userProjects } = useQuery(FETCH_USER_PROJECTS, { 20 | // variables: { admin: parseFloat(1 || -1) } 21 | // }) 22 | // const projectsList = userProjects?.projects 23 | return null 24 | return 25 | } 26 | const AccountPage = props => { 27 | return ( 28 | 29 | 30 | 37 | 42 | 48 | 49 | 50 | {/* */} 58 | 59 | 60 | ) 61 | } 62 | 63 | export default AccountPage 64 | -------------------------------------------------------------------------------- /src/components/create-project-form/modals/CloseModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import { Button, Flex, Text } from 'theme-ui' 4 | 5 | export const CloseModal = ({ showModal, setShowModal }) => ( 6 |
21 | 38 | 41 | Are you sure? 42 | 43 | 51 | 66 | 80 | 81 |
82 | ) 83 | -------------------------------------------------------------------------------- /src/components/account/AccountBody.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Text, Flex, Box } from 'theme-ui' 3 | import React from 'react' 4 | import { Link } from 'gatsby' 5 | import { BsArrowLeft } from 'react-icons/bs' 6 | import styled from '@emotion/styled' 7 | import MyProjects from './myProjects' 8 | const MyAccount = React.lazy(() => import('../../components/account/myAccount')) 9 | const MyDonations = React.lazy(() => 10 | import('../../components/account/myDonations') 11 | ) 12 | const UserSpan = styled.span` 13 | position: relative; 14 | display: grid; 15 | grid-template-columns: repeat(4, auto); 16 | align-items: center; 17 | justify-self: end; 18 | @media (max-width: 1030px) { 19 | grid-row: 1; 20 | grid-column: 3; 21 | } 22 | ` 23 | const SetView = props => { 24 | const { query, projectsList, isSSR, userDonations } = props 25 | const { view, data } = query 26 | switch (view) { 27 | case 'projects': 28 | switch (data) { 29 | case 'all': 30 | return 31 | default: 32 | return 33 | } 34 | case 'donations': 35 | return ( 36 | !isSSR && ( 37 | }> 38 | 39 | 40 | ) 41 | ) 42 | default: 43 | return ( 44 | !isSSR && ( 45 | }> 46 | 52 | 53 | ) 54 | ) 55 | } 56 | } 57 | const AccountBody = props => { 58 | const { query, setQuery, projectsList, isSSR, userDonations } = props 59 | 60 | return ( 61 | 67 | 73 | 74 | ) 75 | } 76 | export default AccountBody 77 | -------------------------------------------------------------------------------- /src/components/create-project-form/inputs/ProjectNameInput.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { Label, Input, Text, Button } from 'theme-ui' 3 | import { animated } from 'react-spring' 4 | 5 | export const ProjectNameInput = ({ 6 | register, 7 | currentValue, 8 | animationStyle 9 | }) => { 10 | const [characterLength, setCharacterLength] = useState( 11 | currentValue ? currentValue.length : 0 12 | ) 13 | return ( 14 | 15 | 24 |
25 | setCharacterLength(e.target.value.length)} 39 | /> 40 | 50 | {characterLength}/55 51 | 52 |
53 | 76 |
77 | ) 78 | } 79 | -------------------------------------------------------------------------------- /src/components/confirmationModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button, Flex, Text } from 'theme-ui' 3 | 4 | const ConfirmationModal = ({ 5 | showModal, 6 | setShowModal, 7 | title, 8 | confirmation, 9 | noMsg 10 | }) => ( 11 |
26 | 43 | 46 | {title} 47 | 48 | 56 | 70 | 84 | 85 |
86 | ) 87 | 88 | export default ConfirmationModal 89 | -------------------------------------------------------------------------------- /src/images/icon-question-mark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/account/projectEdition/confirmationModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button, Flex, Text } from 'theme-ui' 3 | 4 | const ConfirmationModal = ({ 5 | showModal, 6 | setShowModal, 7 | title, 8 | confirmation, 9 | secondary, 10 | noMsg 11 | }) => ( 12 |
28 | 45 | 48 | {title} 49 | 50 | 58 | 72 | 86 | 87 |
88 | ) 89 | 90 | export default ConfirmationModal 91 | -------------------------------------------------------------------------------- /src/components/content/JoinPageHero.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { Link } from 'gatsby' 3 | import { useMediaQuery } from 'react-responsive' 4 | import { Grid, Heading, Text, jsx } from 'theme-ui' 5 | import styled from '@emotion/styled' 6 | 7 | // import decorative graphics 8 | import heroImage from '../../images/people-highfive.svg' 9 | 10 | const HeroSection = styled(Grid)` 11 | grid-template-columns: 1fr auto; 12 | align-items: end; 13 | @media (max-width: 850px) { 14 | grid-template-columns: 1fr; 15 | } 16 | ` 17 | 18 | const HeroImage = styled.img` 19 | padding-right: 3rem; 20 | ` 21 | 22 | const HeroText = styled(Grid)` 23 | grid-template-rows: auto; 24 | justify-self: center; 25 | @media (max-width: 850px) { 26 | } 27 | ` 28 | 29 | const Hero = () => { 30 | const isMobile = useMediaQuery({ query: '(max-width: 850px)' }) 31 | return ( 32 | 33 | 37 | {' '} 38 | 47 | Join our Community{' '} 48 | 49 | 57 | Community of Makers, Building the Future of Giving 58 | 59 | 60 | Giveth is first and foremost a community. We are people working to 61 | build and give well the future we made together. Our project is 62 | open-source, decentralized, altruistic, and community-led. As you've 63 | made it this far, you are probably a Giver and a Maker too. 64 |
65 |
66 | Join one of our platforms below and introduce yourself, so we can 67 | welcome you! 68 |
69 |
70 | {isMobile ? null : } 71 |
72 | ) 73 | } 74 | 75 | export default Hero 76 | -------------------------------------------------------------------------------- /src/components/toast.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text, Spinner } from 'theme-ui' 3 | import { Slide, toast } from 'react-toastify' 4 | import { 5 | IoMdWarning, 6 | IoIosCheckmarkCircle, 7 | IoIosInformationCircle, 8 | IoIosAlert 9 | } from 'react-icons/io' 10 | import 'react-toastify/dist/ReactToastify.css' 11 | import theme from '../gatsby-plugin-theme-ui/index' 12 | import styled from '@emotion/styled' 13 | 14 | export default function Toast({ 15 | content = 'default msg', 16 | type, 17 | noAutoClose, 18 | isLoading, 19 | customPosition 20 | }) { 21 | const config = { 22 | position: customPosition || 'top-right', 23 | autoClose: noAutoClose ? false : 5000, 24 | hideProgressBar: false, 25 | closeOnClick: true, 26 | pauseOnHover: true, 27 | draggable: true, 28 | progress: undefined, 29 | transition: Slide 30 | } 31 | const Content = () => { 32 | let icon = null 33 | const size = '32px' 34 | switch (type) { 35 | case 'error': 36 | icon = 37 | break 38 | case 'success': 39 | icon = 40 | break 41 | case 'warn': 42 | icon = 43 | break 44 | default: 45 | icon = ( 46 | 52 | ) 53 | } 54 | if (isLoading) { 55 | icon = ( 56 | 62 | ) 63 | } 64 | return ( 65 | 66 |
{icon}
67 | 73 | {content} 74 | 75 |
76 | ) 77 | } 78 | if (type) { 79 | return toast[type](, config) 80 | } 81 | return toast.info(, config) 82 | } 83 | -------------------------------------------------------------------------------- /src/services/onBoard.js: -------------------------------------------------------------------------------- 1 | import Notify from 'bnc-notify' 2 | import Onboard from 'bnc-onboard' 3 | 4 | const networkId = process.env.GATSBY_NETWORK_ID 5 | const rpcUrl = process.env.GATSBY_ETHEREUM_NODE 6 | const dappId = process.env.GATSBY_BLOCK_NATIVE_DAPP_ID 7 | const portisKey = process.env.GATSBY_PORTIS_KEY 8 | export function initOnboard (subscriptions, currentChainId) { 9 | return Onboard({ 10 | dappId, 11 | hideBranding: false, 12 | networkId: currentChainId || parseInt(networkId), 13 | // darkMode: true, 14 | subscriptions, 15 | walletSelect: { 16 | wallets: [ 17 | { walletName: 'metamask' }, 18 | { walletName: 'torus' }, 19 | { 20 | walletName: 'portis', 21 | apiKey: portisKey 22 | }, 23 | { 24 | walletName: 'trezor', 25 | appUrl: 'https://giveth.io/', 26 | // email: 'mail@mail.com', 27 | rpcUrl 28 | }, 29 | { 30 | walletName: 'lattice', 31 | appName: 'Giveth 2.0', 32 | rpcUrl 33 | }, 34 | { 35 | walletName: 'ledger', 36 | rpcUrl 37 | }, 38 | { walletName: 'dapper' }, 39 | { walletName: 'coinbase' }, 40 | { walletName: 'status' }, 41 | // { walletName: 'walletLink', rpcUrl }, 42 | // { walletName: 'fortmatic', apiKey: 'pk_test_886ADCAB855632AA' }, 43 | { walletName: 'unilogin' }, 44 | // { walletName: 'squarelink', apiKey: '87288b677f8cfb09a986' }, 45 | { walletName: 'authereum', disableNotifications: true }, 46 | // { walletName: 'trust', rpcUrl }, 47 | { 48 | walletName: 'walletConnect', 49 | infuraKey: process.env.GATSBY_INFURA_ID 50 | }, 51 | { walletName: 'opera' }, 52 | { walletName: 'operaTouch' }, 53 | { walletName: 'imToken', rpcUrl }, 54 | { walletName: 'meetone' }, 55 | { walletName: 'mykey' }, 56 | { walletName: 'wallet.io', rpcUrl } 57 | ] 58 | }, 59 | walletCheck: [ 60 | { checkName: 'derivationPath' }, 61 | { checkName: 'connect' }, 62 | { checkName: 'accounts' }, 63 | { checkName: 'network' }, 64 | { checkName: 'balance', minimumBalance: '100000' } 65 | ] 66 | }) 67 | } 68 | 69 | export function initNotify () { 70 | return Notify({ 71 | dappId, 72 | networkId: parseInt(networkId) 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /src/images/svg/general/decorators/tooltip.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/donate/onlyCrypto_old.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { useState, useEffect } from 'react' 3 | import { Box, Button, Text, jsx } from 'theme-ui' 4 | import styled from '@emotion/styled' 5 | import QRCode from 'qrcode.react' 6 | 7 | const Content = styled.div` 8 | max-width: 41.25rem; 9 | word-wrap: break-word; 10 | ` 11 | 12 | const QRSection = styled.div` 13 | margin: 1.3rem 0 0 0; 14 | @media (max-width: 800px) { 15 | display: flex; 16 | flex-direction: column; 17 | justify-content: center; 18 | align-items: center; 19 | text-align: center; 20 | } 21 | ` 22 | 23 | const QRContainer = styled(Box)` 24 | max-width: 13rem; 25 | border-radius: 12px; 26 | margin: 1rem 0 0 0; 27 | ` 28 | 29 | const AddressContainer = styled.div` 30 | margin: 2rem 0; 31 | @media (max-width: 800px) { 32 | align-self: center; 33 | text-align: center; 34 | } 35 | ` 36 | 37 | const CopyButton = styled(Button)` 38 | width: 100%; 39 | max-width: 20rem; 40 | @media (max-width: 800px) { 41 | width: 70%; 42 | } 43 | ` 44 | 45 | const OnlyCrypto = props => { 46 | const { project, address } = props 47 | const [copyMsg, setCopyMsg] = useState('COPY ADDRESS') 48 | 49 | function copyAddress() { 50 | navigator.clipboard.writeText(address) 51 | setCopyMsg('Address Copied!') 52 | } 53 | 54 | useEffect(() => { 55 | const timer = setTimeout(() => { 56 | setCopyMsg('COPY ADDRESS') 57 | }, 5000) 58 | // Clear timeout if the component is unmounted 59 | return () => timer 60 | }, [copyMsg]) 61 | 62 | return ( 63 | 64 | 65 | 66 | Send ETH or any ERC20 to this address. 67 | 68 | 69 | 100% of donations go directly to the project. 70 | 71 | 72 | 73 | 74 | 75 | 76 | 80 | {address} 81 | 82 | 87 | {copyMsg} 88 | 89 | 90 | 91 | ) 92 | } 93 | 94 | export default OnlyCrypto 95 | -------------------------------------------------------------------------------- /src/images/svg/donation/qr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/apollo/gql/auth.js: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client' 2 | 3 | const VALIDATE_TOKEN = gql` 4 | mutation ValidateToken($token: String!) { 5 | validateToken(token: $token) 6 | } 7 | ` 8 | 9 | const DO_LOGIN = gql` 10 | mutation DoLoginWallet( 11 | $walletAddress: String! 12 | $signature: String! 13 | $email: String 14 | $avatar: String 15 | $name: String 16 | $hostname: String! 17 | $isXDAI: Boolean 18 | ) { 19 | loginWallet( 20 | walletAddress: $walletAddress 21 | signature: $signature 22 | email: $email 23 | avatar: $avatar 24 | name: $name 25 | hostname: $hostname 26 | isXDAI: $isXDAI 27 | ) { 28 | token 29 | user { 30 | id 31 | firstName 32 | lastName 33 | name 34 | email 35 | avatar 36 | url 37 | location 38 | } 39 | } 40 | } 41 | ` 42 | 43 | const GET_USER = gql` 44 | query User($userId: Int!) { 45 | user(userId: $userId) { 46 | id 47 | firstName 48 | lastName 49 | name 50 | email 51 | avatar 52 | walletAddress 53 | url 54 | location 55 | } 56 | } 57 | ` 58 | 59 | const GET_USER_BY_ADDRESS = gql` 60 | query UserByAddress($address: String!) { 61 | userByAddress(address: $address) { 62 | id 63 | firstName 64 | lastName 65 | name 66 | email 67 | avatar 68 | walletAddress 69 | url 70 | location 71 | } 72 | } 73 | ` 74 | 75 | const DO_REGISTER = gql` 76 | mutation DoRegister($name: String!, $email: String!, $password: String!) { 77 | register( 78 | data: { 79 | firstName: $name 80 | lastName: "" 81 | email: $email 82 | password: $password 83 | } 84 | ) { 85 | firstName 86 | email 87 | lastName 88 | } 89 | } 90 | ` 91 | 92 | const UPDATE_USER = gql` 93 | mutation UpdateUser( 94 | $url: String 95 | $name: String 96 | $location: String 97 | $email: String 98 | $lastName: String 99 | $firstName: String 100 | ) { 101 | updateUser( 102 | url: $url 103 | name: $name 104 | location: $location 105 | email: $email 106 | firstName: $firstName 107 | lastName: $lastName 108 | ) 109 | } 110 | ` 111 | 112 | export { 113 | DO_LOGIN, 114 | DO_REGISTER, 115 | GET_USER, 116 | UPDATE_USER, 117 | GET_USER_BY_ADDRESS, 118 | VALIDATE_TOKEN 119 | } 120 | -------------------------------------------------------------------------------- /src/components/account/AccountTop.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Text, Flex, Box } from 'theme-ui' 3 | import { Link } from 'gatsby' 4 | import { BsArrowLeft } from 'react-icons/bs' 5 | import styled from '@emotion/styled' 6 | import iconVerticalLine from '../../images/icon-vertical-line.svg' 7 | import { useMediaQuery } from 'react-responsive' 8 | import theme from '../../gatsby-plugin-theme-ui/index' 9 | 10 | const UserSpan = styled.span` 11 | position: relative; 12 | display: grid; 13 | grid-template-columns: repeat(4, auto); 14 | align-items: center; 15 | justify-self: end; 16 | ` 17 | const CreateLink = styled(Link)` 18 | text-decoration: none; 19 | font-family: 'Red Hat Display', sans-serif; 20 | text-transform: uppercase; 21 | font-weight: 700; 22 | color: ${theme.colors.primary}; 23 | align-self: center; 24 | :hover { 25 | color: ${theme.colors.accent}; 26 | } 27 | ` 28 | const AccountTop = props => { 29 | const isDonation = (props?.query?.view || '') === 'donations' 30 | const isMobile = useMediaQuery({ query: '(max-width: 825px)' }) 31 | return ( 32 | 40 | 51 | 52 | 57 | Giveth 58 | 59 | 60 | 61 | 62 | {isMobile ? null : ( 63 | 64 | 65 | 73 | {isDonation ? 'Donate' : 'Create a project'} 74 | 75 | 76 | 77 | )} 78 | 79 | {/* */} 80 | 81 | 82 | 83 | ) 84 | } 85 | export default AccountTop 86 | -------------------------------------------------------------------------------- /src/components/notification.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text } from 'theme-ui' 3 | import { Slide, toast } from 'react-toastify' 4 | import { 5 | IoMdWarning, 6 | IoIosCheckmarkCircle, 7 | IoIosInformationCircle, 8 | IoIosAlert 9 | } from 'react-icons/io' 10 | import 'react-toastify/dist/ReactToastify.css' 11 | import theme from '../gatsby-plugin-theme-ui/index' 12 | import styled from '@emotion/styled' 13 | 14 | export default function Toast({ content = 'default msg', type, action }) { 15 | const Content = () => { 16 | let icon, bgColor, borderColor 17 | const size = '32px' 18 | switch (type) { 19 | case 'error': 20 | bgColor = theme.colors.red 21 | borderColor = 'secondary' 22 | icon = 23 | break 24 | case 'success': 25 | bgColor = theme.colors.green 26 | borderColor = 'secondary' 27 | icon = 28 | break 29 | case 'warn': 30 | bgColor = theme.colors.yellow 31 | borderColor = theme.colors.warnYellow 32 | icon = 33 | break 34 | default: 35 | bgColor = theme.colors.blue 36 | borderColor = 'secondary' 37 | icon = 38 | } 39 | return ( 40 | 52 | 53 |
{icon}
54 | 55 | {content} 56 | 57 |
58 | {action && ( 59 | 60 | action?.do()} 62 | sx={{ 63 | cursor: 'pointer', 64 | wordBreak: 'break-word', 65 | fontWeight: 'bold', 66 | color: borderColor 67 | }} 68 | > 69 | {action?.title} 70 | 71 | 72 | )} 73 |
74 | ) 75 | } 76 | return 77 | } 78 | -------------------------------------------------------------------------------- /src/images/decorator-leaf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/images/giveth-side-image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/pages/project/[slug].js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import React, { useEffect, useState } from 'react' 3 | import { useApolloClient } from '@apollo/client' 4 | import { jsx, Flex, Text, Spinner } from 'theme-ui' 5 | import { Router } from '@reach/router' 6 | import { FETCH_PROJECT_BY_SLUG } from '../../apollo/gql/projects' 7 | import { ProjectDonatorView } from '../../components/project' 8 | import Layout from '../../components/layout' 9 | import Seo from '../../components/seo' 10 | import { useWallet } from '../../contextProvider/WalletProvider' 11 | 12 | const ShowComponents = ({ projectStatus, slugProject }) => { 13 | const { user } = useWallet() 14 | const isAdmin = slugProject?.admin === user?.id 15 | return ( 16 | <> 17 | {projectStatus && projectStatus !== '5' && !isAdmin ? ( 18 | 19 | 20 | Project Not Available 21 | 22 | 23 | ) : slugProject ? ( 24 | 25 | ) : null} 26 | 27 | ) 28 | } 29 | 30 | const Project = props => { 31 | const id = props.params.slug 32 | const client = useApolloClient() 33 | const [loading, setLoading] = useState(true) 34 | const [slugProject, setSlugProject] = useState(null) 35 | const [projectStatus, setProjectStatus] = useState(null) 36 | useEffect(() => { 37 | const getProject = async () => { 38 | const slug = id 39 | try { 40 | const { data } = await client.query({ 41 | query: FETCH_PROJECT_BY_SLUG, 42 | variables: { 43 | slug: slug.toString() 44 | } 45 | }) 46 | setSlugProject(data?.projectBySlug) 47 | setProjectStatus(data?.projectBySlug?.status?.id) // is active 48 | setLoading(false) 49 | } catch (error) { 50 | console.log({ error }) 51 | setLoading(false) 52 | } 53 | } 54 | if (id) { 55 | getProject() 56 | } else { 57 | setLoading(false) 58 | } 59 | }) 60 | return ( 61 | 62 | 70 | {loading ? ( 71 | 72 | 73 | 74 | ) : ( 75 | 79 | )} 80 | 81 | ) 82 | } 83 | 84 | export default Project 85 | -------------------------------------------------------------------------------- /src/images/svg/create/projectImageGallery4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /static/assets/create/projectImageGallery4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/apollo/gql/donations.js: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag' 2 | const SAVE_DONATION = gql` 3 | mutation( 4 | $chainId: Float! 5 | $fromAddress: String! 6 | $toAddress: String! 7 | $transactionId: String! 8 | $transactionNetworkId: Float! 9 | $amount: Float! 10 | $token: String! 11 | $projectId: Float! 12 | ) { 13 | saveDonation( 14 | chainId: $chainId 15 | fromAddress: $fromAddress 16 | toAddress: $toAddress 17 | transactionId: $transactionId 18 | transactionNetworkId: $transactionNetworkId 19 | amount: $amount 20 | token: $token 21 | projectId: $projectId 22 | ) 23 | } 24 | ` 25 | const SAVE_DONATION_TRANSACTION = gql` 26 | mutation($transactionId: String!, $donationId: Float!) { 27 | saveDonationTransaction( 28 | transactionId: $transactionId 29 | donationId: $donationId 30 | ) 31 | } 32 | ` 33 | const WALLET_DONATIONS = gql` 34 | query donationsFromWallets($fromWalletAddresses: [String!]!) { 35 | donationsFromWallets(fromWalletAddresses: $fromWalletAddresses) { 36 | transactionId 37 | transactionNetworkId 38 | toWalletAddress 39 | fromWalletAddress 40 | anonymous 41 | amount 42 | valueUsd 43 | valueEth 44 | priceEth 45 | priceUsd 46 | user { 47 | id 48 | firstName 49 | lastName 50 | } 51 | project { 52 | title 53 | } 54 | createdAt 55 | currency 56 | } 57 | } 58 | ` 59 | 60 | const PROJECT_DONATIONS = gql` 61 | query donationsToWallets($toWalletAddresses: [String!]!) { 62 | donationsToWallets(toWalletAddresses: $toWalletAddresses) { 63 | transactionId 64 | transactionNetworkId 65 | toWalletAddress 66 | fromWalletAddress 67 | anonymous 68 | amount 69 | valueUsd 70 | valueEth 71 | priceEth 72 | priceUsd 73 | user { 74 | id 75 | name 76 | walletAddress 77 | firstName 78 | lastName 79 | } 80 | project { 81 | title 82 | } 83 | createdAt 84 | currency 85 | } 86 | } 87 | ` 88 | 89 | const USERS_DONATIONS = gql` 90 | query { 91 | donationsByDonor { 92 | transactionId 93 | transactionNetworkId 94 | toWalletAddress 95 | fromWalletAddress 96 | anonymous 97 | amount 98 | valueUsd 99 | user { 100 | id 101 | firstName 102 | lastName 103 | } 104 | project { 105 | title 106 | slug 107 | } 108 | createdAt 109 | currency 110 | } 111 | } 112 | ` 113 | export { 114 | SAVE_DONATION, 115 | USERS_DONATIONS, 116 | WALLET_DONATIONS, 117 | PROJECT_DONATIONS, 118 | SAVE_DONATION_TRANSACTION 119 | } 120 | -------------------------------------------------------------------------------- /src/components/create-project-form/modals/DescriptionInstructionModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import { Button, Text } from 'theme-ui' 4 | 5 | export const DescriptionInstructionModal = ({ showModal, setShowModal }) => ( 6 |
20 | 37 | 40 | How to write a great project description 41 | 42 | 45 | Try to use this structure as a guide when writing the description: 46 | 47 |
    48 | {['who', 'what', 'why', 'where', 'how', 'when'].map(item => { 49 | return ( 50 |
  1. 51 | 58 | {`${item}?`} 59 | 60 |
  2. 61 | ) 62 | })} 63 |
64 | 67 | See how others have done it:{' '} 68 | 69 | Browse examples. 70 | 71 | 72 | 75 | Read this blog post tutorial:
76 | 81 | 82 | "How to write a fundraising project description to increase donations" 83 | 84 | 85 |
86 |
87 | ) 88 | -------------------------------------------------------------------------------- /src/components/seo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Seo component that queries for data with 3 | * Gatsby's useStaticQuery React hook 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from 'react' 9 | import PropTypes from 'prop-types' 10 | import { Helmet } from 'react-helmet' 11 | import { useStaticQuery, graphql } from 'gatsby' 12 | 13 | const DEFAULT_SEO_IMAGE = 'https://i.imgur.com/uPFEgJu.png' 14 | 15 | function Seo({ description, lang, meta, title, image }) { 16 | const { site } = useStaticQuery( 17 | graphql` 18 | query { 19 | site { 20 | siteMetadata { 21 | title 22 | description 23 | author 24 | } 25 | } 26 | } 27 | ` 28 | ) 29 | const metaDescription = description || site.siteMetadata.description 30 | const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/ 31 | let metaImage = image 32 | if (base64Regex.test(image?.split(',')[1])) { 33 | // it's base64, convert >>> this doesnt work 34 | // metaImage = `decoder.php?data=${image}` 35 | metaImage = DEFAULT_SEO_IMAGE 36 | } else if (/^\d+$/.test(metaImage) || !image) { 37 | // it's a number or nothing 38 | metaImage = DEFAULT_SEO_IMAGE 39 | } 40 | // console.log({ metaImage }) 41 | return ( 42 | 87 | ) 88 | } 89 | 90 | Seo.defaultProps = { 91 | lang: 'en', 92 | meta: [], 93 | description: '' 94 | } 95 | 96 | Seo.propTypes = { 97 | description: PropTypes.string, 98 | lang: PropTypes.string, 99 | meta: PropTypes.arrayOf(PropTypes.object), 100 | title: PropTypes.string.isRequired 101 | } 102 | 103 | export default Seo 104 | -------------------------------------------------------------------------------- /src/pages/user.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import React, { useEffect, useState } from 'react' 3 | import { jsx, Text, Flex, Spinner } from 'theme-ui' 4 | import Layout from '../components/layout' 5 | import Seo from '../components/seo' 6 | import { useApolloClient } from '@apollo/client' 7 | import { PublicProfileView } from '../components/user' 8 | import { FETCH_USER_PROJECTS } from '../apollo/gql/projects' 9 | import { GET_USER_BY_ADDRESS } from '../apollo/gql/auth' 10 | import { WALLET_DONATIONS } from '../apollo/gql/donations' 11 | import Web3 from 'web3' 12 | 13 | const User = props => { 14 | const { address } = props 15 | const client = useApolloClient() 16 | 17 | const [loading, setLoading] = useState(true) 18 | const [user, setUser] = useState(null) 19 | const [userDonations, setDonations] = useState(null) 20 | const [userProjects, setProjects] = useState(null) 21 | 22 | useEffect(() => { 23 | const getUser = async () => { 24 | try { 25 | if (user) return null 26 | const { data } = await client.query({ 27 | query: GET_USER_BY_ADDRESS, 28 | variables: { 29 | address: address?.toLowerCase() 30 | } 31 | }) 32 | setUser(data?.userByAddress) 33 | 34 | // GET PROJECTS 35 | const { data: projects } = await client.query({ 36 | query: FETCH_USER_PROJECTS, 37 | variables: { admin: parseFloat(data?.userByAddress?.id || -1) }, 38 | fetchPolicy: 'network-only' 39 | }) 40 | 41 | setProjects( 42 | projects?.projects?.filter(i => i?.admin === data?.userByAddress?.id) 43 | ) 44 | 45 | // GET DONATIONS 46 | const { data: donations } = await client.query({ 47 | query: WALLET_DONATIONS, 48 | variables: { fromWalletAddresses: [address] }, 49 | fetchPolicy: 'network-only' 50 | }) 51 | setDonations(donations?.donationsByDonor) 52 | 53 | setLoading(false) 54 | } catch (error) { 55 | console.log({ error }) 56 | setLoading(false) 57 | } 58 | } 59 | if (address) { 60 | getUser() 61 | } else { 62 | setLoading(false) 63 | } 64 | }) 65 | 66 | return ( 67 | 68 | 69 | {loading ? ( 70 | 71 | 72 | 73 | ) : user ? ( 74 | 79 | ) : ( 80 | 81 | 82 | No user found 83 | 84 | 85 | )} 86 | 87 | ) 88 | } 89 | 90 | export default User 91 | -------------------------------------------------------------------------------- /src/components/project/updatesTab.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { 3 | GET_PROJECT_UPDATES, 4 | ADD_PROJECT_UPDATE 5 | } from '../../apollo/gql/projects' 6 | import { useMutation, useQuery } from '@apollo/client' 7 | import { ProjectContext } from '../../contextProvider/projectProvider' 8 | import LoadingModal from '../loadingModal' 9 | import Toast from '../toast' 10 | import Timeline from './timeline' 11 | 12 | const UpdatesTab = ({ showModal, setShowModal, project, isOwner }) => { 13 | const [addUpdateMutation] = useMutation(ADD_PROJECT_UPDATE) 14 | const [loading, setLoading] = useState(false) 15 | const { currentProjectView, setCurrentProjectView } = React.useContext( 16 | ProjectContext 17 | ) 18 | 19 | const { data, error } = useQuery(GET_PROJECT_UPDATES, { 20 | variables: { 21 | projectId: parseFloat(project?.id), 22 | take: 100, 23 | skip: 0 24 | }, 25 | fetchPolicy: 'network-only' 26 | }) 27 | 28 | useEffect(() => { 29 | if (data) { 30 | setCurrentProjectView({ 31 | ...currentProjectView, 32 | updates: data?.getProjectUpdates 33 | }) 34 | } 35 | }, [data]) 36 | 37 | const addUpdate = async ({ title, content }) => { 38 | try { 39 | if (!title || !content) 40 | return Toast({ content: 'Fields should not be empty', type: 'error' }) 41 | // check if file is too large, avg 4Mb 42 | const contentSize = encodeURI(content).split(/%..|./).length - 1 43 | console.log({ contentSize }) 44 | if (contentSize > 4000000) { 45 | Toast({ 46 | content: `Content is too heavy, it shouldn't exceed 4Mb`, 47 | type: 'error' 48 | }) 49 | return false 50 | } 51 | setLoading(true) 52 | const { data } = await addUpdateMutation({ 53 | variables: { 54 | projectId: parseFloat(project?.id), 55 | title, 56 | content 57 | }, 58 | refetchQueries: [ 59 | { 60 | query: GET_PROJECT_UPDATES, 61 | variables: { 62 | projectId: parseFloat(project?.id), 63 | take: 100, 64 | skip: 0 65 | } 66 | } 67 | ] 68 | }) 69 | console.log({ data }) 70 | setLoading(false) 71 | return data 72 | } catch (error) { 73 | setLoading(false) 74 | console.error('addUpdate') 75 | console.log({ error }) 76 | alert(JSON.stringify(error?.message)) 77 | return false 78 | } 79 | } 80 | 81 | return ( 82 | <> 83 | {loading && } 84 | 91 | 92 | ) 93 | } 94 | 95 | export default UpdatesTab 96 | -------------------------------------------------------------------------------- /src/components/account/index.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import React from 'react' 3 | import { navigate } from 'gatsby' 4 | import { jsx, Text, Flex, Spinner, Box } from 'theme-ui' 5 | import { useQueryParams, StringParam } from 'use-query-params' 6 | import { useQuery } from '@apollo/client' 7 | import styled from '@emotion/styled' 8 | import { useWallet } from '../../contextProvider/WalletProvider' 9 | import { BsArrowLeft } from 'react-icons/bs' 10 | import LoadingModal from '../../components/loadingModal' 11 | import { USERS_DONATIONS } from '../../apollo/gql/donations' 12 | import { FETCH_MY_PROJECTS } from '../../apollo/gql/projects' 13 | import AccountTop from '../../components/account/AccountTop' 14 | import AccountNav from '../../components/account/AccountNav' 15 | import AccountBody from '../../components/account/AccountBody' 16 | 17 | const UserSpan = styled.span` 18 | position: relative; 19 | display: grid; 20 | grid-template-columns: repeat(4, auto); 21 | align-items: center; 22 | justify-self: end; 23 | @media (max-width: 1030px) { 24 | grid-row: 1; 25 | grid-column: 3; 26 | } 27 | ` 28 | 29 | const AccountPage = props => { 30 | const { user, isLoggedIn } = useWallet() 31 | const fromWalletAddress = user.getWalletAddress() 32 | const userWallets = user.walletAddresses 33 | const { data: donations, loading: dataLoading } = useQuery(USERS_DONATIONS, { 34 | fetchPolicy: 'network-only' 35 | }) 36 | const userDonations = donations?.donationsByDonor 37 | 38 | const { data: userProjects, loading: projectsLoading, error } = useQuery( 39 | FETCH_MY_PROJECTS, 40 | { 41 | fetchPolicy: 'network-only' 42 | } 43 | ) 44 | const projectsList = userProjects?.myProjects 45 | const [query, setQuery] = useQueryParams({ 46 | view: StringParam, 47 | data: StringParam 48 | }) 49 | const isSSR = typeof window === 'undefined' 50 | 51 | if (dataLoading || projectsLoading) { 52 | return ( 53 | <> 54 | 55 | 56 | 57 | 58 | ) 59 | } 60 | 61 | if (!isLoggedIn) { 62 | navigate('/', { state: { welcome: true } }) 63 | return null 64 | } 65 | 66 | return ( 67 | <> 68 | 69 | 76 | 82 | 89 | 90 | 91 | ) 92 | } 93 | 94 | export default AccountPage 95 | -------------------------------------------------------------------------------- /src/components/tooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text } from 'theme-ui' 3 | import styled from '@emotion/styled' 4 | import TooltipImg from '../images/svg/general/decorators/tooltip.svg' 5 | 6 | const Tooltip = styled.div` 7 | margin: 0 0.5rem; 8 | position: relative; 9 | 10 | .tooltip-text { 11 | visibility: hidden; 12 | width: 180px; 13 | background-color: white; 14 | color: black; 15 | text-align: center; 16 | border-radius: 6px; 17 | padding: 1rem; 18 | margin: 0 0 0 5px; 19 | 20 | text-align: left; 21 | 22 | /* Position the tooltip */ 23 | position: absolute; 24 | margin-top: 5px; 25 | z-index: 1; 26 | } 27 | 28 | .tooltip-arrow { 29 | visibility: hidden; 30 | width: 0; 31 | height: 0; 32 | border-style: solid; 33 | position: absolute; 34 | margin: 5px; 35 | border-color: transparent; 36 | z-index: 1; 37 | } 38 | 39 | &:hover { 40 | .tooltip-text { 41 | visibility: visible; 42 | } 43 | .tooltip-arrow { 44 | visibility: visible; 45 | } 46 | } 47 | @media (max-width: 600px) { 48 | .tooltip-text { 49 | margin: 10% 0 0 0; 50 | left: 10%; 51 | } 52 | } 53 | 54 | &.right .tooltip-text { 55 | top: -40px; 56 | margin-left: 10px; 57 | } 58 | 59 | &.left .tooltip-text { 60 | top: -40px; 61 | right: 32px; 62 | } 63 | 64 | &.top .tooltip-text { 65 | bottom: 34px; 66 | left: -81px; 67 | } 68 | 69 | &.bottom .tooltip-text { 70 | top: 25px; 71 | left: -81px; 72 | } 73 | 74 | &.top .tooltip-arrow { 75 | top: -14px; 76 | border-width: 5px 5px 0; 77 | border-top-color: #af9bd3; 78 | } 79 | 80 | &.right .tooltip-arrow { 81 | top: 0px; 82 | left: auto; 83 | margin-left: 23px; 84 | border-width: 5px 5px 5px 0; 85 | border-right-color: #af9bd3; 86 | } 87 | 88 | &.bottom .tooltip-arrow { 89 | top: 20px; 90 | border-width: 0 5px 5px; 91 | border-bottom-color: #af9bd3; 92 | } 93 | 94 | &.left .tooltip-arrow { 95 | top: 0px; 96 | right: 22px; 97 | border-width: 5px 0 5px 5px; 98 | border-left-color: #af9bd3; 99 | } 100 | ` 101 | 102 | export default function ToolTip ({ 103 | content, 104 | contentStyle, 105 | textStyle, 106 | isArrow, 107 | placement 108 | }) { 109 | return ( 110 | 118 | 119 | {isArrow &&
} 120 | 121 | 122 | {content} 123 | 124 | 125 | 126 | ) 127 | } 128 | -------------------------------------------------------------------------------- /src/images/icon-streamline-gas.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/signInMetamaskModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Text } from 'theme-ui' 3 | import Modal from 'react-modal' 4 | 5 | import decoratorClouds from '../images/decorator-clouds.svg' 6 | import metamaskLogo from '../images/logos/metamask-fox.svg' 7 | 8 | const customStyles = { 9 | overlay: { 10 | position: 'fixed', 11 | zIndex: 4, 12 | top: 0, 13 | left: 0, 14 | right: 0, 15 | bottom: 0, 16 | backgroundColor: 'rgba(0, 0, 0, 0.25)', 17 | backdropFilter: 'blur(2px)', 18 | '-webkit-backdrop-filter': 'blur(2px)' 19 | }, 20 | content: { 21 | top: '50%', 22 | left: '50%', 23 | right: 'auto', 24 | bottom: 'auto', 25 | borderRadius: '12px', 26 | borderColor: 'transparent', 27 | marginRight: '-50%', 28 | transform: 'translate(-50%, -50%)' 29 | } 30 | } 31 | 32 | function LoginModal (props) { 33 | React.useEffect(() => { 34 | Modal.setAppElement('body') 35 | }) 36 | return ( 37 |
38 | props.close()} 41 | style={customStyles} 42 | contentLabel='Sign In Metamask Modal' 43 | > 44 | 51 | signup-clouds 56 | { 65 | e.preventDefault() 66 | props.close() 67 | }} 68 | > 69 | Close 70 | 71 | 79 | 80 | Connecting to Metamask 81 | 82 | 83 | Please confirm sign in through your MetaMask popup window. 84 | 85 | Metamask logo 94 | 95 | 96 | 97 |
98 | ) 99 | } 100 | 101 | export default LoginModal 102 | -------------------------------------------------------------------------------- /src/components/content/SocialNetworks.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from '@emotion/styled' 3 | import { 4 | FaMedium, 5 | FaComments, 6 | FaTwitter, 7 | FaGithub, 8 | FaReddit, 9 | FaFacebook, 10 | FaYoutube, 11 | FaWikipediaW, 12 | FaLinkedin 13 | } from 'react-icons/fa' 14 | 15 | import theme from '../../gatsby-plugin-theme-ui/index' 16 | 17 | const SocialContainer = styled.div` 18 | @media (max-width: 850px) { 19 | max-width: 100vw; 20 | } 21 | ` 22 | 23 | const LinkContainer = styled.div` 24 | display: grid; 25 | grid-template-columns: repeat(auto-fit, minmax(24px, 1fr)); 26 | justify-content: space-evenly; 27 | width: 344px; 28 | @media (max-width: 850px) { 29 | max-width: 100vw; 30 | } 31 | ` 32 | 33 | const SocialLink = styled.a` 34 | width: 24px; 35 | justify-self: start; 36 | transition: 0.8s cubic-bezier(0.2, 0.8, 0.2, 1); 37 | color: ${theme.colors.bodyDark}; 38 | 39 | :hover { 40 | transform: scale(1.2) translateY(-3px); 41 | color: ${theme.colors.accent}; 42 | } 43 | 44 | @media (max-width: 850px) { 45 | justify-self: center; 46 | } 47 | ` 48 | 49 | const SocialNetworks = ({ compressed }) => { 50 | if (compressed) { 51 | return ( 52 | <> 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ) 67 | } 68 | return ( 69 | 70 | 71 | 72 | 73 | 74 | 75 | 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 | export default SocialNetworks 101 | -------------------------------------------------------------------------------- /src/components/create-project-form/inputs/ProjectAdminInput.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { Label, Input, Flex, Text, Button } from 'theme-ui' 3 | import { animated } from 'react-spring' 4 | 5 | export const ProjectAdminInput = ({ 6 | register, 7 | currentValue, 8 | animationStyle, 9 | goBack 10 | }) => { 11 | const [characterLength, setCharacterLength] = useState( 12 | currentValue ? currentValue.length : 0 13 | ) 14 | return ( 15 | 16 | 25 |
26 | setCharacterLength(e.target.value.length)} 40 | /> 41 | 51 | {characterLength}/55 52 | 53 |
54 | 61 | 84 | 106 | 107 |
108 | ) 109 | } 110 | -------------------------------------------------------------------------------- /src/components/donate/inProgressModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import { Button, Flex, Text, Spinner } from 'theme-ui' 4 | import { getEtherscanPrefix } from '../../utils' 5 | import { useWallet } from '../../contextProvider/WalletProvider' 6 | import theme from '../../gatsby-plugin-theme-ui/index' 7 | 8 | const etherscanPrefix = getEtherscanPrefix() 9 | const InProgressModal = ({ showModal, setShowModal, txHash }) => { 10 | const { isLoggedIn } = useWallet() 11 | if (!showModal) return null 12 | return ( 13 | 30 | 49 | 50 | 51 | Donation is still in progress... 52 | 53 | 62 | Transaction has been submitted and is waiting for confirmation. 63 | 67 | {' '} 68 | View on Etherscan 69 | 70 | 71 | 72 | You can safely close this window and return to Homepage.{' '} 73 | {isLoggedIn && 74 | `Your 75 | transaction will show in ${' '}`} 76 | {isLoggedIn && ( 77 | 81 | My Account. 82 | 83 | )} 84 | 85 | 86 | 100 | 101 | ) 102 | } 103 | 104 | export default InProgressModal 105 | -------------------------------------------------------------------------------- /src/components/user/profileHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Avatar from '../avatar' 3 | import { Text, Box, Link, Flex } from 'theme-ui' 4 | import { getEtherscanPrefix } from '../../utils' 5 | 6 | export const ProfileHeader = props => { 7 | const { user, donations, projects } = props 8 | const etherscanPrefix = getEtherscanPrefix() 9 | const TitleBox = ({ title, content }) => { 10 | return ( 11 | 20 | 28 | {title} 29 | 30 | {content} 31 | 32 | ) 33 | } 34 | 35 | return ( 36 | 44 | 54 | 59 | 60 | {user?.name} 61 | 65 | 73 | {user?.walletAddress} 74 | 75 | 76 | 85 | 93 | {user?.url} 94 | 95 | 96 | 97 | 98 | 104 | 105 | 106 | 107 | 108 | ) 109 | } 110 | -------------------------------------------------------------------------------- /src/images/decorator-circles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/richTextInput.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import ReactQuill, { Quill } from 'react-quill' 3 | 4 | import * as Emoji from 'quill-emoji' 5 | 6 | import 'react-quill/dist/quill.snow.css' 7 | import 'quill-emoji/dist/quill-emoji.css' 8 | import QuillImageDropAndPaste from 'quill-image-drop-and-paste' 9 | 10 | window.Quill = Quill 11 | 12 | const ImageResize = require('quill-image-resize-module').default 13 | 14 | Quill.register('modules/emoji', Emoji) 15 | Quill.register('modules/ImageResize', ImageResize) 16 | Quill.register('modules/imageDropAndPaste', QuillImageDropAndPaste) 17 | 18 | const QuillVideo = Quill.import('formats/video') 19 | const BlockEmbed = Quill.import('blots/block/embed') 20 | 21 | const VIDEO_ATTRIBUTES = ['height', 'width'] 22 | 23 | // provides a custom div wrapper around the default Video blot 24 | class Video extends BlockEmbed { 25 | static create(value) { 26 | const iframeNode = QuillVideo.create(value) 27 | const node = super.create() 28 | node.appendChild(iframeNode) 29 | return node 30 | } 31 | 32 | static formats(domNode) { 33 | const iframe = domNode.getElementsByTagName('iframe')[0] 34 | return VIDEO_ATTRIBUTES.reduce(function (formats, attribute) { 35 | if (iframe.hasAttribute(attribute)) { 36 | formats[attribute] = iframe.getAttribute(attribute) 37 | } 38 | return formats 39 | }, {}) 40 | } 41 | 42 | static value(domNode) { 43 | return domNode.getElementsByTagName('iframe')[0].getAttribute('src') 44 | } 45 | 46 | format(name, value) { 47 | if (VIDEO_ATTRIBUTES.indexOf(name) > -1) { 48 | if (value) { 49 | this.domNode.setAttribute(name, value) 50 | } else { 51 | this.domNode.removeAttribute(name) 52 | } 53 | } else { 54 | super.format(name, value) 55 | } 56 | } 57 | } 58 | 59 | Video.blotName = 'video' 60 | Video.className = 'ql-video-wrapper' 61 | Video.tagName = 'DIV' 62 | 63 | Quill.register(Video, true) 64 | 65 | const modules = { 66 | toolbar: [ 67 | [{ header: '1' }, { header: '2' }], 68 | [{ size: [] }], 69 | ['bold', 'italic', 'underline', 'strike', 'blockquote'], 70 | [ 71 | { list: 'ordered' }, 72 | { list: 'bullet' }, 73 | { indent: '-1' }, 74 | { indent: '+1' } 75 | ], 76 | ['link', 'image', 'video'], 77 | // ['emoji'], 78 | ['clean'] 79 | ], 80 | 'emoji-toolbar': true, 81 | 'emoji-textarea': false, 82 | 'emoji-shortname': true, 83 | clipboard: { 84 | // toggle to add extra line breaks when pasting HTML: 85 | matchVisual: false 86 | }, 87 | imageDropAndPaste: {}, 88 | ImageResize: {} 89 | } 90 | 91 | const formats = [ 92 | 'header', 93 | 'font', 94 | 'size', 95 | 'bold', 96 | 'italic', 97 | 'underline', 98 | 'strike', 99 | 'blockquote', 100 | 'list', 101 | 'bullet', 102 | 'indent', 103 | 'link', 104 | 'image', 105 | 'video' 106 | ] 107 | 108 | function TextRichWithQuill(props) { 109 | // console.log({ value }) 110 | return ( 111 | 123 | ) 124 | } 125 | 126 | export default TextRichWithQuill 127 | -------------------------------------------------------------------------------- /src/components/create-project-form/inputs/ProjectCategotyInput.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Checkbox, Label, Flex, Box, Text, Button } from 'theme-ui' 3 | import { animated } from 'react-spring' 4 | 5 | export const ProjectCategoryInput = ({ 6 | register, 7 | currentValue, 8 | categoryList = [], 9 | animationStyle, 10 | goBack 11 | }) => { 12 | return ( 13 | 14 | 23 | 32 | You can select multiple categories 33 | 34 | 41 | {categoryList?.map(category => { 42 | return ( 43 | 62 | ) 63 | })} 64 | 65 | 72 | 94 | 117 | 118 | 119 | ) 120 | } 121 | -------------------------------------------------------------------------------- /src/entities/user.ts: -------------------------------------------------------------------------------- 1 | 2 | import { ProjectNameInput } from '../components/create-project-form/inputs/ProjectNameInput'; 3 | import { isAddressENS } from '../services/wallet'; 4 | import { Location } from '@reach/router'; 5 | import { 6 | getLocalStorageUserLabel, 7 | getLocalStorageTokenLabel 8 | } from '../services/auth' 9 | 10 | const gatsbyUser = getLocalStorageUserLabel() 11 | const tokenLabel = getLocalStorageTokenLabel() 12 | 13 | export default class User { 14 | id: number 15 | token: string 16 | activeWalletIndex: number 17 | walletAddresses: string[] 18 | activeWallet: string 19 | email?: string 20 | firstName?: string 21 | lastName?: string 22 | name?: string 23 | password?: string 24 | avatar?: string 25 | url?: string 26 | location?: string 27 | loginType: string 28 | confirmed: boolean 29 | walletType: string 30 | 31 | constructor(walletType, initUser) { 32 | this.walletType = walletType 33 | this.walletAddresses = [] 34 | 35 | if(initUser) { 36 | this.parseInitUser(initUser) 37 | } 38 | } 39 | 40 | parseInitUser(initUser) { 41 | if(this.walletType === 'torus') { 42 | this.parseTorusUser(initUser) 43 | } else { 44 | this.walletType = initUser.walletType 45 | this.walletAddresses = initUser.walletAddresses 46 | this.id = initUser.id 47 | this.token = initUser.token 48 | this.parseDbUser(initUser) 49 | } 50 | } 51 | 52 | /** 53 | * From the database 54 | * @param initUser 55 | */ 56 | parseDbUser(dbUser) { 57 | this.avatar = dbUser.avatar 58 | this.email = dbUser.email 59 | this.id = dbUser.id 60 | this.firstName = dbUser.firstName 61 | this.lastName = dbUser.lastName 62 | this.location = dbUser.location 63 | this.name = dbUser.name 64 | this.url = dbUser.url 65 | } 66 | 67 | setUserId(userId) { 68 | this.id = userId 69 | } 70 | 71 | setToken(token) { 72 | this.token = token 73 | 74 | localStorage.setItem(tokenLabel, token) 75 | } 76 | 77 | addWalletAddress(address, activeWallet) { 78 | this.walletAddresses.push(address) 79 | 80 | if(activeWallet) { 81 | this.activeWalletIndex = this.walletAddresses.indexOf(address) 82 | } 83 | 84 | 85 | } 86 | 87 | getAuthObject() { 88 | return { 89 | addresses: this.walletAddresses 90 | } 91 | } 92 | 93 | getName() { 94 | function truncAddress (address) { 95 | return `${address.substring(0, 5)}...${address.substring( 96 | address.length - 4, 97 | address.length 98 | )}` 99 | } 100 | 101 | return this.name ? this.name.toUpperCase() : truncAddress(this.getWalletAddress()) 102 | // return /(.+)@(.+){2,}\.(.+){2,}/.test(this.name) 103 | // ? this.name?.toUpperCase() 104 | // : this.name 105 | } 106 | getWalletAddress() { 107 | return this.walletAddresses && this.walletAddresses.length > 0 ? this.walletAddresses[0] : '' 108 | } 109 | // organisations: Organisation[] 110 | 111 | parseTorusUser(torusUser) { 112 | if(this.walletType !== 'torus') throw Error ('Only valid for Torus wallets') 113 | this.avatar = torusUser.profileImage || torusUser.avatar 114 | this.name = torusUser.name 115 | this.email = torusUser.email 116 | this.id = torusUser.id 117 | // this.addWalletAddress(walletAddress, true) 118 | torusUser.walletAddresses.forEach(address => { 119 | this.addWalletAddress(address, true) 120 | }) 121 | } 122 | } --------------------------------------------------------------------------------