├── 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
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 |
38 |
41 | maxAmount.gte(value) || 'Donation amount is more than your balance'
42 | })}
43 | name='amount'
44 | mb={3}
45 | placeholder='Amount'
46 | />
47 |
48 |
49 | Donate
50 |
51 |
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 | {/* this.setState({ isStopped: true })}
39 | >
40 | stop
41 |
42 | this.setState({ isStopped: false })}
45 | >
46 | play
47 |
48 | this.setState({ isPaused: !this.state.isPaused })}
51 | >
52 | pause
53 | */}
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 | {/* this.setState({ isStopped: true })}
39 | >
40 | stop
41 |
42 | this.setState({ isStopped: false })}
45 | >
46 | play
47 |
48 | this.setState({ isPaused: !this.state.isPaused })}
51 | >
52 | pause
53 | */}
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 |
setShowModal(false)}
31 | aria-label='close'
32 | sx={{
33 | position: 'absolute',
34 | top: '10px',
35 | right: '32px',
36 | fontSize: '3',
37 | fontFamily: 'body',
38 | color: 'secondary',
39 | background: 'unset',
40 | cursor: 'pointer'
41 | }}
42 | >
43 | Close
44 |
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 | {
19 | e.preventDefault()
20 | setQuery({ tab: name })
21 | }}
22 | >
23 |
32 | {name}
33 |
34 |
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 |
26 | BROWSE PROJECTS
27 |
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 |
25 | ethEnabled
26 | ? setIsComponentVisible(!isComponentVisible)
27 | : login({ walletProvider: 'torus' })
28 | }
29 | >
30 | Sign in
31 |
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 | setShowModal(false)}
24 | aria-label='close'
25 | sx={{
26 | position: 'absolute',
27 | top: '32px',
28 | right: '32px',
29 | fontSize: '3',
30 | fontFamily: 'body',
31 | color: 'secondary',
32 | background: 'unset',
33 | cursor: 'pointer'
34 | }}
35 | >
36 | Close
37 |
38 |
41 | Are you sure?
42 |
43 |
51 |
62 |
63 | Yes
64 |
65 |
66 | setShowModal(false)}
70 | variant='nofill'
71 | sx={{
72 | color: 'secondary',
73 | width: '140px',
74 | height: '52px',
75 | border: '2px solid #AAAFCA'
76 | }}
77 | >
78 | No
79 |
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 |
22 | What's the name of your project?
23 |
24 |
25 | setCharacterLength(e.target.value.length)}
39 | />
40 |
50 | {characterLength}/55
51 |
52 |
53 |
64 |
73 | NEXT
74 |
75 |
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 | setShowModal(false)}
29 | aria-label='close'
30 | sx={{
31 | position: 'absolute',
32 | top: '32px',
33 | right: '32px',
34 | fontSize: '3',
35 | fontFamily: 'body',
36 | color: 'secondary',
37 | background: 'unset',
38 | cursor: 'pointer'
39 | }}
40 | >
41 | Close
42 |
43 |
46 | {title}
47 |
48 |
56 | confirmation?.do()}
67 | >
68 | {confirmation?.title}
69 |
70 | setShowModal(false)}
74 | variant='nofill'
75 | sx={{
76 | color: 'secondary',
77 | width: '140px',
78 | height: '52px',
79 | border: '2px solid #AAAFCA'
80 | }}
81 | >
82 | No
83 |
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 | setShowModal(false)}
31 | aria-label='close'
32 | sx={{
33 | position: 'absolute',
34 | top: '32px',
35 | right: '32px',
36 | fontSize: '3',
37 | fontFamily: 'body',
38 | color: 'secondary',
39 | background: 'unset',
40 | cursor: 'pointer'
41 | }}
42 | >
43 | Close
44 |
45 |
48 | {title}
49 |
50 |
58 | confirmation?.do()}
69 | >
70 | {confirmation?.title}
71 |
72 | secondary?.do()}
76 | variant='nofill'
77 | sx={{
78 | color: 'secondary',
79 | width: '140px',
80 | height: '52px',
81 | border: '2px solid #AAAFCA'
82 | }}
83 | >
84 | {secondary?.title}
85 |
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 |
setShowModal(false)}
23 | aria-label='close'
24 | sx={{
25 | position: 'absolute',
26 | top: '32px',
27 | right: '32px',
28 | fontSize: '3',
29 | fontFamily: 'body',
30 | color: 'secondary',
31 | background: 'unset',
32 | cursor: 'pointer'
33 | }}
34 | >
35 | Close
36 |
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 |
51 |
58 | {`${item}?`}
59 |
60 |
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 |
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 |
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 |
23 | What's the name of the organization or administrator of the project?
24 |
25 |
26 | setCharacterLength(e.target.value.length)}
40 | />
41 |
51 | {characterLength}/55
52 |
53 |
54 |
61 |
72 |
81 | NEXT
82 |
83 |
84 |
95 |
103 | Back
104 |
105 |
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 | {
33 | setShowModal(false)
34 | }}
35 | aria-label='close'
36 | sx={{
37 | position: 'absolute',
38 | top: '32px',
39 | right: '32px',
40 | fontSize: '3',
41 | fontFamily: 'body',
42 | color: 'secondary',
43 | background: 'unset',
44 | cursor: 'pointer'
45 | }}
46 | >
47 | Close
48 |
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 | (window.location.href = '/')}
97 | >
98 | GO TO HOMEPAGE
99 |
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 |
21 | Please select a category
22 |
23 |
32 | You can select multiple categories
33 |
34 |
41 | {categoryList?.map(category => {
42 | return (
43 |
47 |
60 | {category.value}
61 |
62 | )
63 | })}
64 |
65 |
72 |
82 |
91 | NEXT
92 |
93 |
94 |
106 |
114 | Back
115 |
116 |
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 | }
--------------------------------------------------------------------------------