├── .env
├── .gitignore
├── README.md
├── components
├── .env
├── Box.js
├── Boxes.js
├── Boxx.jsx
├── CWload-new.js
├── CWload.js
├── CWload2.js
├── Canvas3.jsx
├── Cart.tsx
├── CartSummary.tsx
├── CheckoutForm.tsx
├── ClearCart.tsx
├── ConnectWallet.js
├── CustomDonationInput.tsx
├── Draggable.jsx
├── ElementsForm.tsx
├── Floor.jsx
├── Layout.tsx
├── LightBulb.jsx
├── Modal
│ ├── index.js
│ └── modal.css
├── OrbitControls.jsx
├── PrintObject.tsx
├── Products.tsx
├── StripeTestCards.tsx
├── firebase
│ └── client.tsx
└── thirdwebsdk.js
├── config
└── index.ts
├── contexts
├── Address
│ ├── index.jsx
│ └── reducer.js
└── web3
│ └── index.js
├── data
└── products.ts
├── lib
└── firebase.js
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages
├── 404.tsx
├── _app.tsx
├── _app.xjsx
├── admin
│ ├── edit
│ │ ├── [id].js
│ │ └── index.js
│ └── post.js
├── api
│ ├── checkout_sessions
│ │ ├── [id].ts
│ │ ├── cart.ts
│ │ └── index.ts
│ ├── payment_intents
│ │ └── index.ts
│ ├── user.js
│ └── webhooks
│ │ └── index.ts
├── boxes.tsx
├── edit.js
├── faq.tsx
├── index.tsx
├── post.js
├── result.tsx
├── shop.tsx
├── thanks.tsx
├── web3.xjs
├── whitelist-thanks.tsx
└── whitelist.tsx
├── public
├── Archidao_wearable.js
├── Test.js
├── archidao.png
├── archidao_wearable.bin
├── archidao_wearable.glb
├── archidao_wearable.gltf
├── archidao_wearable_2.gltf
├── black_ready.jpg
├── checkout-one-time-payments.svg
├── checkout_demo.gif
├── draw-with-compass.svg
├── elements-card-payment.svg
├── elements_demo.gif
├── logo.png
├── male_2.glb
├── male_2.gltf
├── nft_.png
├── preview.png
├── shopping_cart_demo.gif
├── social_card.png
├── test.gltf
└── use-shopping-cart.png
├── store
├── context.js
├── globalStateProvider.js
└── useGlobalState.js
├── styles.css
├── styles
└── Home.module.css
├── tsconfig.json
├── utils
├── api-helpers.ts
├── get-stripejs.ts
├── index.js
└── stripe-helpers.ts
├── with-stripe-typescript-app.zip
└── yarn.lock
/.env:
--------------------------------------------------------------------------------
1 | # Stripe keys
2 | # https://dashboard.stripe.com/apikeys
3 | NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51JEY9A4DPeJl1lYzNLvnJS2E6zQHyIXOvwYXD9D34apyGU6xFrErlR9QHTA1z2u8OwCdd31pL1Q0TgltNfLTBGbr00THgtSgJY
4 | STRIPE_SECRET_KEY=sk_test_51JEY9A4DPeJl1lYzXuTamAP7fSgy7kg4KJLNVozrRGp91wWbSso36YKmYF2D0WBtoBgzewPjo1QWMCa3atUKlA4y00wEDGWrlW
5 | STRIPE_PAYMENT_DESCRIPTION='ArchiDAO NFT'
6 | # https://stripe.com/docs/webhooks/signatures
7 | STRIPE_WEBHOOK_SECRET=whsec_1234
8 | INFURA_ID = 10499f16823b4f2c9ef9ca2536c6fab7
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # bad code
4 |
5 | # dependencies
6 | /node_modules
7 | /.pnp
8 | .pnp.js
9 |
10 | # testing
11 | /coverage
12 |
13 | # next.js
14 | /.next/
15 | /out/
16 |
17 | # production
18 | /build
19 |
20 | # misc
21 | .DS_Store
22 | *.pem
23 |
24 | # debug
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log*
28 |
29 | # local env files
30 | .env.local
31 | .env.development.local
32 | .env.test.local
33 | .env.production.local
34 | serviceAccountKey.json
35 |
36 | # vercel
37 | .vercel
38 |
39 | .vercel
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Next Stripe Web3 Three JS
2 |
3 | A Next JS project that pulls together all the libraries needed for a slick website with web3 and web2 payment integrations. Not yet slick but we're getting there.
4 |
5 | `yarn dev` should get you going.
6 |
7 | ## Tasks
8 | In progress:
9 | - database (gcp + orbitdb maybe) @jb4earth
10 |
11 | Help wanted:
12 | - CSS fixes
13 | - Three JS updates
14 |
15 | License: MIT
16 |
--------------------------------------------------------------------------------
/components/.env:
--------------------------------------------------------------------------------
1 | ### remove the '#' to use the environment variables
2 | export PRIVATE_KEY=31390d749ec2eef68713a7b18f9141655f936aff74193b22cb4394c21a8da4a4
3 | export WEB3_INFURA_PROJECT_ID=0ad6386686934f6585cd8eefc9739c04
4 |
5 |
6 | ### Optional - don't uncomment if you don't know what they do!
7 | # export ETHERSCAN_TOKEN=asdfasdfasdf
8 | export IPFS_URL=http://127.0.0.1:5001
9 | export UPLOAD_IPFS=true
10 | # export PINATA_API_KEY='asdfasdfs'
11 | # export PINATA_API_SECRET='asdfasdfsdf'
12 |
--------------------------------------------------------------------------------
/components/Box.js:
--------------------------------------------------------------------------------
1 | import { useRef, useState } from 'react';
2 | import { useFrame, useThree } from '@react-three/fiber';
3 | import { Box as NativeBox } from '@react-three/drei';
4 |
5 | export default function Box(props) {
6 | const mesh = useRef();
7 | const { viewport } = useThree();
8 |
9 | const [hovered, setHover] = useState(false);
10 | const [active, setActive] = useState(false);
11 |
12 | useFrame(({ mouse }) => {
13 | mesh.current.rotation.x = mesh.current.rotation.y += 0.01;
14 | const x = (mouse.x * viewport.width) / 2;
15 | const y = (mouse.y * viewport.height) / 2;
16 | mesh.current.position.set(x, y, 0);
17 | });
18 |
19 | return (
20 | setActive(!active)}
26 | onPointerOver={() => setHover(true)}
27 | onPointerOut={() => setHover(false)}
28 | >
29 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/components/Boxes.js:
--------------------------------------------------------------------------------
1 | import { Canvas } from '@react-three/fiber'
2 | import { OrbitControls } from '@react-three/drei'
3 | import Box from './Box'
4 |
5 | const Boxes = () => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | )
16 | }
17 |
18 | export default Boxes
19 |
--------------------------------------------------------------------------------
/components/Boxx.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useLoader } from "@react-three/fiber";
3 | import { TextureLoader } from "three";
4 |
5 | function Box(props) {
6 | const texture = useLoader(TextureLoader, "/texture.jpg");
7 | return (
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default Box;
16 |
--------------------------------------------------------------------------------
/components/CWload-new.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | useAddress,
4 |
5 | } from '@thirdweb-dev/react';
6 |
7 |
8 | export const CWload = () => {
9 |
10 | const address = useAddress();
11 |
12 | return address
13 | };
14 |
--------------------------------------------------------------------------------
/components/CWload.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | useAddress,
4 |
5 | } from '@thirdweb-dev/react';
6 | import { NextPage } from 'next'
7 | import Link from 'next/link'
8 | import Layout from '../components/Layout'
9 | import Head from "next/head";
10 |
11 |
12 | import { setDoc,doc,collection, getFirestore,updateDoc, arrayUnion } from '@firebase/firestore';
13 | import { AddressContext } from "../contexts/Address"
14 | import { useState } from 'react';
15 | import { firestore } from '../components/firebase/client';
16 |
17 | import React from "react"
18 |
19 |
20 |
21 |
22 | export const CWload = (context) => {
23 |
24 | const address = useAddress();
25 | if (address) {
26 | const timestamp = Date.now().toString();
27 | console.log(timestamp)
28 | // updateDoc(doc(firestore, "crypto_logins", String(address)), {
29 | // [context]: arrayUnion(String(timestamp)) }).catch(()=>{ setDoc(doc(firestore, "crypto_logins", String(address)), {
30 | // [context]: arrayUnion(String(timestamp)) });})
31 |
32 |
33 | } else {}
34 |
35 |
36 | return address
37 | };
38 |
--------------------------------------------------------------------------------
/components/CWload2.js:
--------------------------------------------------------------------------------
1 | import {
2 |
3 | useAddress,
4 |
5 | } from '@thirdweb-dev/react';
6 | import { NextPage } from 'next'
7 | import Link from 'next/link'
8 | import Layout from '../components/Layout'
9 | import Head from "next/head";
10 |
11 |
12 | import { setDoc,doc,collection, getFirestore,updateDoc, arrayUnion } from '@firebase/firestore';
13 | import { AddressContext } from "../contexts/Address"
14 | import { useState } from 'react';
15 | import { firestore } from '../components/firebase/client';
16 |
17 | import React from "react"
18 |
19 |
20 |
21 |
22 | export const CWload = (context) => {
23 |
24 | const address = useAddress();
25 | if (address) {
26 | const timestamp = Date.now().toString();
27 | console.log(timestamp)
28 | updateDoc(doc(firestore, "crypto_logins", String(address)), {
29 | [context]: arrayUnion(String(timestamp)) }).catch(()=>{ setDoc(doc(firestore, "crypto_logins", String(address)), {
30 | [context]: arrayUnion(String(timestamp)) });})
31 |
32 |
33 | } else {}
34 |
35 |
36 | return address
37 | };
38 |
--------------------------------------------------------------------------------
/components/Canvas3.jsx:
--------------------------------------------------------------------------------
1 | import css from "../styles/Home.module.css";
2 | import { useLoader, useFrame,useThree } from "@react-three/fiber";
3 | import { Canvas } from "@react-three/fiber";
4 | import Box from "./Boxx";
5 | import OrbitControls from "./OrbitControls";
6 | import LightBulb from "./LightBulb";
7 | import Floor from "./Floor";
8 | import Draggable from "./Draggable";
9 | import {Suspense} from "react";
10 | import Model from '../public/Archidao_wearable.js'
11 | import React, {useState} from "react";
12 | import { useMouse } from "rooks";
13 | function MyRotatingBox() {
14 | const ref = React.useRef()
15 |
16 | const myMesh = React.useRef();
17 | const mouseLightMesh = React.useRef();
18 |
19 | const { viewport } = useThree();
20 |
21 | const [hovered, setHover] = useState(false);
22 | const [active, setActive] = useState(false);
23 | const [intensity, setIntensity] = useState(false);
24 | const { x, y } = useMouse();
25 | useFrame(({ clock }) => {
26 | const a = clock.getElapsedTime();
27 | myMesh.current.rotation.y = a*-.5;
28 |
29 | // mesh.current.rotation.x = mesh.current.rotation.y += 0.01;
30 | const x2 = (x / viewport.width);
31 | const y2 = (y / viewport.height);
32 | // console.log(docY)
33 | // console.log(posX)
34 | // console.log(elX)
35 | mouseLightMesh.current.position.set(x2*3-60, -(-y2*2.5+40), 6);
36 | });
37 | return (
38 | <>
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | >
55 | );
56 | }
57 | const light_info = [
58 | {position: [-20,0,0],color:'green',intensity:.5},
59 | {position: [-10,5,-10],color:'purple',intensity:.5},
60 | {position: [20,5,10],color:'blue',intensity:.5},
61 | {position: [0,10,10],color:'pink',intensity:.5},
62 | ]
63 |
64 |
65 | export default function Canvas3() {
66 | return (
67 |
68 |
75 | {light_info.map((lightx) => (
76 |
77 |
78 |
79 | ))}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | );
89 | }
90 |
--------------------------------------------------------------------------------
/components/Cart.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode } from 'react'
2 | import { CartProvider } from 'use-shopping-cart/react'
3 | import * as config from '../config'
4 |
5 | const Cart = ({ children }: { children: ReactNode }) => (
6 |
11 | <>{children}>
12 |
13 | )
14 |
15 | export default Cart
16 |
--------------------------------------------------------------------------------
/components/CartSummary.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback } from 'react'
2 | import {
3 | useNetwork,
4 | useAddress,
5 | } from '@thirdweb-dev/react';
6 | import Web3 from 'web3';
7 | import StripeTestCards from '../components/StripeTestCards'
8 | import { CWload } from '../components/CWload';
9 | import { AddressContext } from "../contexts/Address"
10 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
11 | import { useShoppingCart } from 'use-shopping-cart/react'
12 | import { fetchPostJSON } from '../utils/api-helpers'
13 | const CartSummary = () => {
14 | const [loading, setLoading] = useState(false)
15 | const [result, setResult] = useState(true)
16 | const [cartEmpty, setCartEmpty] = useState(true)
17 | const [errorMessage, setErrorMessage] = useState('')
18 | const {
19 | formattedTotalPrice,
20 | cartCount,
21 | clearCart,
22 | cartDetails,
23 | redirectToCheckout,
24 | } = useShoppingCart()
25 |
26 | useEffect(() => setCartEmpty(!cartCount), [cartCount])
27 | // useEffect(() => setResult(!cartCount), [cartCount])
28 |
29 | const [ state, dispatch ] = React.useContext(AddressContext)
30 | console.log(state)
31 | console.log(state.address)
32 | console.log('cartsumm.jsx')
33 |
34 |
35 | const handleCheckout: React.FormEventHandler = async (
36 | event
37 | ) => {
38 | event.preventDefault()
39 | setLoading(true)
40 | setErrorMessage('')
41 |
42 | console.log(state.address)
43 | console.log('got hrere')
44 |
45 |
46 | const response = await fetchPostJSON(
47 | '/api/checkout_sessions/cart',
48 | cartDetails
49 | )
50 |
51 | if (response.statusCode > 399) {
52 | console.error(response.message)
53 | setErrorMessage(response.message)
54 | setLoading(false)
55 | return
56 | }
57 |
58 | redirectToCheckout({ sessionId: response.id })
59 | }
60 | console.log(state)
61 | console.log(state.active)
62 | console.log('CS pre retren')
63 | console.log(cartEmpty)
64 | if (CWload('CartSummary.tsx')){ return (
65 |
110 | )}else{return(please connect wallet )}
111 |
112 | }
113 |
114 | export default CartSummary
115 |
--------------------------------------------------------------------------------
/components/CheckoutForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 |
3 | import CustomDonationInput from '../components/CustomDonationInput'
4 | import StripeTestCards from '../components/StripeTestCards'
5 |
6 | import getStripe from '../utils/get-stripejs'
7 | import { fetchPostJSON } from '../utils/api-helpers'
8 | import { formatAmountForDisplay } from '../utils/stripe-helpers'
9 | import * as config from '../config'
10 |
11 | const CheckoutForm = () => {
12 | const [loading, setLoading] = useState(false)
13 | const [input, setInput] = useState({
14 | customDonation: Math.round(config.MAX_AMOUNT / config.AMOUNT_STEP),
15 | })
16 |
17 | const handleInputChange: React.ChangeEventHandler = (e) =>
18 | setInput({
19 | ...input,
20 | [e.currentTarget.name]: e.currentTarget.value,
21 | })
22 |
23 | const handleSubmit: React.FormEventHandler = async (e) => {
24 | e.preventDefault()
25 | setLoading(true)
26 | // Create a Checkout Session.
27 | const response = await fetchPostJSON('/api/checkout_sessions', {
28 | amount: input.customDonation,
29 | })
30 |
31 | if (response.statusCode === 500) {
32 | console.error(response.message)
33 | return
34 | }
35 |
36 | // Redirect to Checkout.
37 | const stripe = await getStripe()
38 | const { error } = await stripe!.redirectToCheckout({
39 | // Make the id field from the Checkout Session creation API response
40 | // available to this file, so you can provide it as parameter here
41 | // instead of the {{CHECKOUT_SESSION_ID}} placeholder.
42 | sessionId: response.id,
43 | })
44 | // If `redirectToCheckout` fails due to a browser or network
45 | // error, display the localized error message to your customer
46 | // using `error.message`.
47 | console.warn(error.message)
48 | setLoading(false)
49 | }
50 |
51 | return (
52 |
72 | )
73 | }
74 |
75 | export default CheckoutForm
76 |
--------------------------------------------------------------------------------
/components/ClearCart.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import { useShoppingCart } from 'use-shopping-cart/react'
3 |
4 | export default function ClearCart() {
5 | const { clearCart } = useShoppingCart()
6 |
7 | useEffect(() => clearCart(), [clearCart])
8 |
9 | return Cart cleared.
10 | }
11 |
--------------------------------------------------------------------------------
/components/ConnectWallet.js:
--------------------------------------------------------------------------------
1 | import {
2 | useMetamask,
3 | useWalletConnect,
4 | useCoinbaseWallet,
5 | useNetwork,
6 | useAddress,
7 | useDisconnect,
8 | } from '@thirdweb-dev/react';
9 | import { AddressContext } from "../contexts/Address"
10 | import React from "react"
11 | // import {store, useGlobalState} from 'state-pool';
12 | //
13 | // store.setState("user",{address: '', transaction: '', active:''});
14 |
15 |
16 | // import { Web3Context } from "../contexts/web3"
17 |
18 | export const ConnectWallet = () => {
19 | const connectWithCoinbaseWallet = useCoinbaseWallet();
20 | const connectWithMetamask = useMetamask();
21 | const connectWithWalletConnect = useWalletConnect();
22 | const disconnectWallet = useDisconnect();
23 | // const address =
24 | const network = useNetwork();
25 |
26 |
27 |
28 | const [ state, setState ] = React.useContext(AddressContext)
29 |
30 | const hold_address = useAddress();
31 |
32 | // const [user, setUser, updateUser] = useGlobalState("user");
33 | // updateUser(function(user){
34 | // user.address = state.address
35 | // })
36 | // console.log(user.address)
37 | // console.log(state.address)
38 | // console.log('CW first.js')
39 |
40 |
41 |
42 |
43 | const disconnectWalletX = () => {
44 | // state.address = false
45 | setState({address: false,active:false})
46 | state.active = false
47 | state.address = false
48 |
49 | disconnectWallet()
50 | console.log(state)
51 | console.log('ConnectWallet.js disconnect')
52 | }
53 |
54 | const walletConnected = () => {
55 | if (state.active === false) {
56 | setState({address: hold_address, active: true})
57 | // dispatch({address: hold_address})
58 | // dispatch({active:true})
59 | state.address = hold_address
60 | state.active = true
61 | console.log(state)
62 | console.log('ConnectWallet.js connect')
63 | }
64 | // console.log(state.address)
65 | // console.log(state)
66 | // const {addressx,setAddress} = React.useContext(Web3Context)
67 | // if (state.address !== addressx){setAddress(state.address)}
68 | // else {console.log('why render?')}
69 | // console.log('pre-button render')
70 | }
71 | // If a wallet is connected, show address, chainId and disconnect button
72 | if (hold_address) {
73 | walletConnected()
74 | return (
75 | <>
76 | disconnectWalletX()}>{String(hold_address).slice(0,5)+'...'+String(hold_address).slice(-3)}
77 | >
78 | );
79 | }
80 |
81 | // If no wallet is connected, show connect wallet options
82 | return (
83 | <>
84 | connectWithCoinbaseWallet()}>
85 | Coinbase Wallet
86 |
87 | connectWithMetamask()}>MetaMask
88 | connectWithWalletConnect()}>
89 | WalletConnect
90 |
91 | >
92 | );
93 | };
94 |
--------------------------------------------------------------------------------
/components/CustomDonationInput.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { formatAmountForDisplay } from '../utils/stripe-helpers'
3 |
4 | type Props = {
5 | name: string
6 | value: number
7 | min: number
8 | max: number
9 | currency: string
10 | step: number
11 | onChange: (e: React.ChangeEvent) => void
12 | className?: string
13 | }
14 |
15 | const CustomDonationInput = ({
16 | name,
17 | value,
18 | min,
19 | max,
20 | currency,
21 | step,
22 | onChange,
23 | className,
24 | }: Props) => (
25 |
26 | Custom donation amount ({formatAmountForDisplay(min, currency)}-
27 | {formatAmountForDisplay(max, currency)}):
28 |
38 |
47 |
48 | )
49 |
50 | export default CustomDonationInput
51 |
--------------------------------------------------------------------------------
/components/Draggable.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from "react";
2 | import { extend, useThree } from "@react-three/fiber";
3 | import { DragControls } from "three/examples/jsm/controls/DragControls";
4 |
5 | extend({ DragControls });
6 |
7 | function Draggable(props) {
8 | const groupRef = useRef();
9 | const controlsRef = useRef();
10 | const [objects, setObjects] = useState();
11 | const { camera, gl, scene } = useThree();
12 | useEffect(() => {
13 | setObjects(groupRef.current.children);
14 | }, [groupRef]);
15 |
16 | useEffect(() => {
17 | controlsRef.current.addEventListener("hoveron", () => {
18 | scene.orbitControls.enabled = false;
19 | });
20 | controlsRef.current.addEventListener("hoveroff", () => {
21 | scene.orbitControls.enabled = true;
22 | });
23 | }, [objects]);
24 | return (
25 |
26 |
27 | {props.children}
28 |
29 | );
30 | }
31 |
32 | export default Draggable;
33 |
--------------------------------------------------------------------------------
/components/ElementsForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, FC } from 'react'
2 |
3 | import CustomDonationInput from '../components/CustomDonationInput'
4 | import StripeTestCards from '../components/StripeTestCards'
5 | import PrintObject from '../components/PrintObject'
6 |
7 | import { fetchPostJSON } from '../utils/api-helpers'
8 | import {
9 | formatAmountForDisplay,
10 | formatAmountFromStripe,
11 | } from '../utils/stripe-helpers'
12 | import * as config from '../config'
13 |
14 | import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js'
15 | import { PaymentIntent } from '@stripe/stripe-js'
16 |
17 | const ElementsForm: FC<{
18 | paymentIntent?: PaymentIntent | null
19 | }> = ({ paymentIntent = null }) => {
20 | const defaultAmout = paymentIntent
21 | ? formatAmountFromStripe(paymentIntent.amount, paymentIntent.currency)
22 | : Math.round(config.MAX_AMOUNT / config.AMOUNT_STEP)
23 | const [input, setInput] = useState({
24 | customDonation: defaultAmout,
25 | cardholderName: '',
26 | })
27 | const [paymentType, setPaymentType] = useState('')
28 | const [payment, setPayment] = useState({ status: 'initial' })
29 | const [errorMessage, setErrorMessage] = useState('')
30 | const stripe = useStripe()
31 | const elements = useElements()
32 |
33 | const PaymentStatus = ({ status }: { status: string }) => {
34 | switch (status) {
35 | case 'processing':
36 | case 'requires_payment_method':
37 | case 'requires_confirmation':
38 | return Processing...
39 |
40 | case 'requires_action':
41 | return Authenticating...
42 |
43 | case 'succeeded':
44 | return Payment Succeeded 🥳
45 |
46 | case 'error':
47 | return (
48 | <>
49 | Error 😭
50 | {errorMessage}
51 | >
52 | )
53 |
54 | default:
55 | return null
56 | }
57 | }
58 |
59 | const handleInputChange: React.ChangeEventHandler = (e) =>
60 | setInput({
61 | ...input,
62 | [e.currentTarget.name]: e.currentTarget.value,
63 | })
64 |
65 | const handleSubmit: React.FormEventHandler = async (e) => {
66 | e.preventDefault()
67 | // Abort if form isn't valid
68 | if (!e.currentTarget.reportValidity()) return
69 | if (!elements) return
70 | setPayment({ status: 'processing' })
71 |
72 | // Create a PaymentIntent with the specified amount.
73 | const response = await fetchPostJSON('/api/payment_intents', {
74 | amount: input.customDonation,
75 | payment_intent_id: paymentIntent?.id,
76 | })
77 | setPayment(response)
78 |
79 | if (response.statusCode === 500) {
80 | setPayment({ status: 'error' })
81 | setErrorMessage(response.message)
82 | return
83 | }
84 |
85 | // Use your card Element with other Stripe.js APIs
86 | const { error } = await stripe!.confirmPayment({
87 | elements,
88 | confirmParams: {
89 | return_url: 'http://localhost:3000/donate-with-elements',
90 | payment_method_data: {
91 | billing_details: {
92 | name: input.cardholderName,
93 | },
94 | },
95 | },
96 | })
97 |
98 | if (error) {
99 | setPayment({ status: 'error' })
100 | setErrorMessage(error.message ?? 'An unknown error occurred')
101 | } else if (paymentIntent) {
102 | setPayment(paymentIntent)
103 | }
104 | }
105 |
106 | return (
107 | <>
108 |
151 |
152 |
153 | >
154 | )
155 | }
156 |
157 | export default ElementsForm
158 |
--------------------------------------------------------------------------------
/components/Floor.jsx:
--------------------------------------------------------------------------------
1 | //components/Floor.jsx
2 |
3 | import React from "react";
4 |
5 | function Floor(props) {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Floor;
15 |
--------------------------------------------------------------------------------
/components/Layout.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode,useContext } from 'react'
2 | import Head from 'next/head'
3 | import Link from 'next/link'
4 | import { library } from "@fortawesome/fontawesome-svg-core";
5 | import Canvas3 from './Canvas3'
6 | import { fab,faTwitter,faDiscord,faGithub } from '@fortawesome/free-brands-svg-icons'
7 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
8 | // import { } from '@fortawesome/fontawesome-free-solid'
9 | import { ConnectWallet } from '../components/ConnectWallet';
10 | import { AddressContext } from "../contexts/Address"
11 |
12 |
13 |
14 | library.add(faTwitter,faDiscord,faGithub);
15 | type Props = {
16 | children: ReactNode
17 | title?: string
18 | }
19 |
20 | const Layout = ({
21 | children,
22 | title = 'ArchiDAO',
23 | }: Props) => (
24 | <>
25 |
26 |
27 |
28 | {title}
29 |
30 |
31 |
32 |
33 |
34 |
38 |
42 |
43 |
44 |
45 |
62 | {children}
63 |
64 |
65 |
86 | >
87 | )
88 |
89 | export default Layout
90 |
--------------------------------------------------------------------------------
/components/LightBulb.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function LightBulb(props) {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 | );
11 | }
12 |
13 | export default LightBulb;
14 |
--------------------------------------------------------------------------------
/components/Modal/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./modal.css";
3 | import PropTypes from "prop-types";
4 |
5 | export default class Modal extends React.Component {
6 | onClose = e => {
7 | this.props.onClose && this.props.onClose(e);
8 | };
9 | render() {
10 | if (!this.props.show) {
11 | return null;
12 | }
13 | return (
14 |
15 |
Modal Window
16 |
{this.props.children}
17 |
18 |
19 | close
20 |
21 |
22 |
23 | );
24 | }
25 | }
26 | Modal.propTypes = {
27 | onClose: PropTypes.func.isRequired,
28 | show: PropTypes.bool.isRequired
29 | };
30 |
--------------------------------------------------------------------------------
/components/Modal/modal.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | }
5 | body {
6 | background: #eee;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | }
11 | .modal {
12 | width: 500px;
13 | background: white;
14 | border: 1px solid #ccc;
15 | transition: 1.1s ease-out;
16 | box-shadow: -2rem 2rem 2rem rgba(0, 0, 0, 0.2);
17 | filter: blur(0);
18 | transform: scale(1);
19 | opacity: 1;
20 | visibility: visible;
21 | }
22 | .modal.off {
23 | opacity: 0;
24 | visibility: hidden;
25 | filter: blur(8px);
26 | transform: scale(0.33);
27 | box-shadow: 1rem 0 0 rgba(0, 0, 0, 0.2);
28 | }
29 | @supports (offset-rotation: 0deg) {
30 | offset-rotation: 0deg;
31 | offset-path: path("M 250,100 S -300,500 -700,-200");
32 | .modal.off {
33 | offset-distance: 100%;
34 | }
35 | }
36 | @media (prefers-reduced-motion) {
37 | .modal {
38 | offset-path: none;
39 | }
40 | }
41 | .modal h2 {
42 | border-bottom: 1px solid #ccc;
43 | padding: 1rem;
44 | margin: 0;
45 | }
46 | .modal .content {
47 | padding: 1rem;
48 | }
49 | .modal .actions {
50 | border-top: 1px solid #ccc;
51 | background: #eee;
52 | padding: 0.5rem 1rem;
53 | }
54 | .modal .actions button {
55 | border: 0;
56 | background: #78f89f;
57 | border-radius: 5px;
58 | padding: 0.5rem 1rem;
59 | font-size: 0.8rem;
60 | line-height: 1;
61 | }
62 | #centered-toggle-button {
63 | position: absolute;
64 | }
65 |
--------------------------------------------------------------------------------
/components/OrbitControls.jsx:
--------------------------------------------------------------------------------
1 | // components/OrbitControls.jsx
2 |
3 | import React from "react";
4 | import { extend, useThree } from "@react-three/fiber";
5 | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
6 |
7 | extend({ OrbitControls });
8 |
9 | function Controls(props) {
10 | const { camera, gl } = useThree();
11 | return ;
12 | }
13 |
14 | export default Controls;
15 |
--------------------------------------------------------------------------------
/components/PrintObject.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | type Props = {
4 | content: object
5 | }
6 |
7 | const PrintObject = ({ content }: Props) => {
8 | const formattedContent: string = JSON.stringify(content, null, 2)
9 | return {formattedContent}
10 | }
11 |
12 | export default PrintObject
13 |
--------------------------------------------------------------------------------
/components/Products.tsx:
--------------------------------------------------------------------------------
1 | import products from '../data/products'
2 | import { formatCurrencyString } from 'use-shopping-cart'
3 | import { useShoppingCart } from 'use-shopping-cart/react'
4 | import { CWload } from '../components/CWload';
5 | // import {FontAwesomeIcon} from fortawesome;
6 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
7 | // import { library } from '@fortawesome/fontawesome-svg-core'
8 | // import { fab } from '@fortawesome/free-brands-svg-icons'
9 | // import { faCheckSquare, faCoffee } from '@fortawesome/free-solid-svg-icons'
10 | // library.add(fab, faCheckSquare, faCoffee)
11 | // // this babel macros brings in a module called moduled and next doesnt like that (which makes sense because using a built in name is a bad idea)
12 | // import { solid, regular, brands } from '@fortawesome/fontawesome-svg-core/import.macro'
13 | import React, { useState, useEffect, useCallback } from 'react'
14 |
15 |
16 | const Products = () => {
17 | const { addItem, removeItem, incrementItem, decrementItem,cartCount } = useShoppingCart()
18 | const [minusOn, setMinus] = useState(false)
19 | const [plusOn, setPlus] = useState(true)
20 | const address = CWload('Products.tsx')
21 | // try{decrementItem(product.id)}
22 | const minusAction = (product) => {
23 |
24 | if (cartCount > 1) {
25 | decrementItem(product.id)
26 | } else { setMinus(false)}
27 | checkButtons(cartCount)
28 |
29 | }
30 |
31 | const plusAction = (product) => {
32 | console.log(product)
33 | if (cartCount < 10) {
34 | addItem(product)
35 | } else { setPlus(false) }
36 | checkButtons(cartCount)
37 | }
38 |
39 | const checkButtons = (count) => {
40 | console.log(count)
41 | if (count > 1 ) {setMinus(true)}
42 | if (count < 10 ) {setPlus(true)}
43 | }
44 |
45 | if (!address) {return (
46 |
47 | {products.map((product) => (
48 |
49 |
50 |
{product.name}
51 |
52 | {formatCurrencyString({
53 | value: product.price,
54 | currency: product.currency,
55 | })}
56 |
57 |
58 | ))}
59 | )
60 | } else{
61 | return (
62 |
63 | {products.map((product) => (
64 |
65 |
66 |
{product.name}
67 |
68 | {formatCurrencyString({
69 | value: product.price,
70 | currency: product.currency,
71 | })}
72 |
73 |
minusAction(product)}
76 | disabled={!address || !(cartCount > 1)}
77 | >
78 | -
79 |
80 |
{
83 | console.log(product)
84 | addItem(product)
85 | }}
86 | disabled={!address || !(cartCount < 10) }
87 | >
88 | +
89 |
90 |
91 | ))}
92 |
93 | )}
94 | }
95 |
96 | export default Products
97 |
--------------------------------------------------------------------------------
/components/StripeTestCards.tsx:
--------------------------------------------------------------------------------
1 | const StripeTestCards = () => {
2 | return (
3 |
4 | Use any of the{' '}
5 |
10 | Stripe test cards
11 | {' '}
12 | for this demo, e.g.{' '}
13 |
14 | 4242 4242 4242 4242
15 |
16 | .
17 |
18 | )
19 | }
20 |
21 | export default StripeTestCards
22 |
--------------------------------------------------------------------------------
/components/firebase/client.tsx:
--------------------------------------------------------------------------------
1 | // Import the functions you need from the SDKs you need
2 | import { initializeApp } from "@firebase/app";
3 | import { getFirestore } from "@firebase/firestore";
4 | // TODO: Add SDKs for Firebase products that you want to use
5 | // https://firebase.google.com/docs/web/setup#available-libraries
6 |
7 | // Your web app's Firebase configuration
8 | // For Firebase JS SDK v7.20.0 and later, measurementId is optional
9 | const firebaseConfig = {
10 | apiKey: "AIzaSyDbbgvth9u0l4zE390Ko1WAYd9Fs5gsjDQ",
11 | authDomain: "archidao.firebaseapp.com",
12 | projectId: "archidao",
13 | storageBucket: "archidao.appspot.com",
14 | messagingSenderId: "1064854491749",
15 | appId: "1:1064854491749:web:cf5efaebe7555167532c8c",
16 | measurementId: "G-4JFQ60YZP3"
17 | };
18 |
19 | // Initialize Firebase
20 | const app = initializeApp(firebaseConfig);
21 | const firestore = getFirestore(app);
22 |
23 | export {firestore}
24 |
--------------------------------------------------------------------------------
/components/thirdwebsdk.js:
--------------------------------------------------------------------------------
1 | import { ThirdwebSDK } from "@thirdweb-dev/sdk";
2 | import ethers from "ethers";
3 | import dotenv from "dotenv";
4 | dotenv.config();
5 | if (!process.env.PRIVATE_KEY || process.env.PRIVATE_KEY === "") {
6 | console.log("🛑 Private key not found.");
7 | }
8 | if (!process.env.ALCHEMY_API_URL || process.env.ALCHEMY_API_URL === "") {
9 | console.log("🛑 Alchemy API URL not found.");
10 | }
11 | if (!process.env.WALLET_ADDRESS || process.env.WALLET_ADDRESS === "") {
12 | console.log("🛑 Wallet Address not found.");
13 | }
14 | const sdk = new ThirdwebSDK(
15 | new ethers.Wallet(
16 | process.env.PRIVATE_KEY,
17 | ethers.getDefaultProvider(process.env.ALCHEMY_API_URL)
18 | )
19 | );
20 | (async () => {
21 | try {
22 | const address = await sdk.getSigner().getAddress();
23 | console.log("SDK initialized by address:", address);
24 | } catch (err) {
25 | console.error("Failed to get the address", err);
26 | process.exit(1);
27 | }
28 | })();
29 | export default sdk;
30 |
--------------------------------------------------------------------------------
/config/index.ts:
--------------------------------------------------------------------------------
1 | export const CURRENCY = 'usd'
2 | // Set your amount limits: Use float for decimal currencies and
3 | // Integer for zero-decimal currencies: https://stripe.com/docs/currencies#zero-decimal.
4 | export const MIN_AMOUNT = 10.0
5 | export const MAX_AMOUNT = 5000.0
6 | export const AMOUNT_STEP = 5.0
7 |
--------------------------------------------------------------------------------
/contexts/Address/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {useState, createContext} from "react"
2 | import { reducer, initialState } from "./reducer"
3 |
4 | export const AddressContext = createContext()
5 |
6 | export const AddressProvider = ({ children }) => {
7 | const [state, setState] = useState(initialState)
8 |
9 | return (
10 |
11 | { children }
12 |
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/contexts/Address/reducer.js:
--------------------------------------------------------------------------------
1 | export const reducer = (state, action) => {
2 | switch (action.type) {
3 | case "toggle_button":
4 | return {
5 | ...state,
6 | active: !state.active
7 | }
8 |
9 | default:
10 | return state
11 | }
12 | }
13 |
14 | export const initialState = {
15 | active: 'init',
16 | address: 'init',
17 | }
18 |
--------------------------------------------------------------------------------
/contexts/web3/index.js:
--------------------------------------------------------------------------------
1 | import {createContext,useState} from "react"
2 |
3 | export const Web3Context = createContext()
4 |
5 | export function Web3Provider({ children }){
6 | const [addressx , setAddressx] = useState({address: '',active: false, transaction: ''})
7 | const setAddress = (address) => {setAddressx({address:address})}
8 | return (
9 |
10 | { children }
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/data/products.ts:
--------------------------------------------------------------------------------
1 | const product = [
2 | {
3 | name: 'ArchiDAO NFT',
4 | description: 'ArchiDAO Wearable',
5 | id: 'archida_nft_0000',
6 | price: 9000,
7 | image:
8 | 'https://ipfs.io/ipfs/QmPYAPNFB373TrM9TJN59RDuZgSpUDW9qvqBktaSS4vDEH?filename=nft_.png',
9 | attribution: 'Photo by Archidao.io',
10 | currency: 'USD',
11 | },
12 | ]
13 | export default product
14 |
--------------------------------------------------------------------------------
/lib/firebase.js:
--------------------------------------------------------------------------------
1 | import * as admin from 'firebase-admin';
2 |
3 | if (!admin.apps.length) {
4 | admin.initializeApp({
5 | credential: admin.credential.cert({
6 | projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
7 | clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
8 | privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n')
9 | })
10 | });
11 | }
12 |
13 | const db = admin.firestore();
14 |
15 | export { db };
16 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | typescript: {
3 | // !! WARN !!
4 | // Dangerously allow production builds to successfully complete even if
5 | // your project has type errors.
6 | // !! WARN !!
7 | ignoreBuildErrors: true,
8 | },
9 | future: {
10 | webpack5: true, // by default, if you customize webpack config, they switch back to version 4.
11 | // Looks like backward compatibility approach.
12 |
13 | },
14 | webpack(config) {
15 | config.experiments = { topLevelAwait: true,layers:true };
16 | config.resolve.fallback = {
17 | ...config.resolve.fallback, // if you miss it, all the other options in fallback, specified
18 | // by next.js will be dropped. Doesn't make much sense, but how it is
19 | fs: false, // the solution
20 | os: false,
21 | child_process: false,
22 | module: "empty",
23 | };
24 |
25 | return config;
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "SET PORT=8000 && next",
5 | "build": "next build",
6 | "start": "next start"
7 | },
8 | "dependencies": {
9 | "@firebase/analytics": "^0.7.9",
10 | "@firebase/app": "^0.7.24",
11 | "@firebase/firestore": "^3.4.9",
12 | "@fortawesome/fontawesome-free": "^6.1.1",
13 | "@fortawesome/fontawesome-svg-core": "^6.1.1",
14 | "@fortawesome/free-brands-svg-icons": "^6.1.1",
15 | "@fortawesome/free-solid-svg-icons": "^6.1.1",
16 | "@fortawesome/react-fontawesome": "^0.1.18",
17 | "@react-hook/mouse-position": "^4.1.3",
18 | "@react-three/cannon": "^6.3.0",
19 | "@react-three/drei": "^9.7.1",
20 | "@react-three/fiber": "^8.0.13",
21 | "@reduxjs/toolkit": "^1.8.1",
22 | "@stripe/react-stripe-js": "1.7.0",
23 | "@stripe/stripe-js": "1.22.0",
24 | "@thirdweb-dev/react": "^2.2.6",
25 | "@thirdweb-dev/sdk": "^2.2.4",
26 | "axios": "^0.27.2",
27 | "babel-plugin-macros": "^3.1.0",
28 | "browser-env": "^3.3.0",
29 | "dashify": "^2.0.0",
30 | "dotenv": "^16.0.1",
31 | "ethers": "^5.6.5",
32 | "firebase": "9.8.1",
33 | "firebase-admin": "^10.2.0",
34 | "fontawesome": "^5.6.3",
35 | "fs": "^0.0.1-security",
36 | "fx": "^20.0.2",
37 | "micro": "^9.3.4",
38 | "micro-cors": "^0.1.1",
39 | "net": "^1.0.2",
40 | "next": "^12.1.6",
41 | "react": "^18.0.0-rc.3",
42 | "react-colorful": "^5.5.1",
43 | "react-dom": "^18.0.0-rc.3",
44 | "react-firebase-hooks": "^5.0.3",
45 | "react-firebaseui": "^6.0.0",
46 | "rooks": "^5.11.0",
47 | "state-pool": "^0.7.1",
48 | "stripe": "8.200.0",
49 | "swr": "^1.3.0",
50 | "three": "^0.140.0",
51 | "three-stdlib": "^2.10.1",
52 | "tls": "^0.0.1",
53 | "use-shopping-cart": "3.0.5",
54 | "valtio": "^1.6.0",
55 | "vercel": "^24.2.0",
56 | "web3": "^1.7.3"
57 | },
58 | "devDependencies": {
59 | "@types/micro": "^7.3.3",
60 | "@types/micro-cors": "^0.1.0",
61 | "@types/node": "^13.1.2",
62 | "@types/react": "^16.9.17",
63 | "typescript": "4.5.5"
64 | },
65 | "browser": {
66 | "fs": false,
67 | "path": false,
68 | "os": false,
69 | "child_process": false
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next'
2 | import Link from 'next/link'
3 | import Layout from '../components/Layout'
4 |
5 | const IndexPage: NextPage = () => {
6 | return (
7 |
8 |
9 | 404 | NOTHING HERE
10 |
11 | )
12 | }
13 |
14 | export default IndexPage
15 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { AppProps } from 'next/app'
2 | import { ThirdwebProvider } from '@thirdweb-dev/react';
3 | import { AddressProvider } from "../contexts/Address"
4 | import { Web3Provider } from "../contexts/web3"
5 |
6 | import ReactDOM from 'react-dom'
7 | import { library } from '@fortawesome/fontawesome-svg-core'
8 | import { fab } from '@fortawesome/free-brands-svg-icons'
9 | import { faCheckSquare, faCoffee } from '@fortawesome/free-solid-svg-icons'
10 |
11 | library.add(fab, faCheckSquare, faCoffee)
12 |
13 |
14 |
15 | import '../styles.css'
16 |
17 | function MyApp({ Component, pageProps }: AppProps) {
18 | const desiredChainId = 80001;
19 | /* Make sure that your app is wrazpped with these contexts.
20 | * If you're using React, you'll have to replace the Component setup with {children}
21 | */
22 | return (
23 | <>
24 |
25 |
26 |
27 | {/* @ts-ignore */}
28 |
29 |
30 |
31 |
32 | >
33 | );
34 | }
35 |
36 | export default MyApp
37 |
--------------------------------------------------------------------------------
/pages/_app.xjsx:
--------------------------------------------------------------------------------
1 | import { ChainId, ThirdwebProvider } from "@thirdweb-dev/react";
2 |
3 | const MyApp = () => {
4 | return (
5 |
6 |
7 |
8 | );
9 | };
10 |
11 | export default MyApp
12 |
--------------------------------------------------------------------------------
/pages/admin/edit/[id].js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import { useRouter } from 'next/router'
3 | import dashify from 'dashify';
4 | import axios from 'axios';
5 |
6 | const EditEntry = () => {
7 | const router = useRouter()
8 | const [content, setContent] = useState({
9 | title: undefined,
10 | body: undefined,
11 | })
12 |
13 | useEffect(async () => {
14 | const { id } = router.query;
15 | if (id) {
16 | const res = await axios.get(`/api/entry/${id}`);
17 | const { title, body } = res.data;
18 | setContent({
19 | title,
20 | body
21 | })
22 | }
23 | }, [router])
24 |
25 | const onChange = (e) => {
26 | const { value, name } = e.target;
27 | setContent(prevState => ({ ...prevState, [name]: value }));
28 | }
29 |
30 | const onSubmit = async (e) => {
31 | const { id } = router.query
32 | const { title, body } = content;
33 | console.log(id, title, body);
34 | await axios.put(`/api/entry/${id}`, {
35 | slug: dashify(title),
36 | title,
37 | body,
38 | });
39 | }
40 |
41 | const onDelete = async () => {
42 | const { id } = router.query;
43 | await axios.delete(`/api/entry/${id}`);
44 | router.back();
45 | }
46 |
47 | return (
48 |
49 | Title
50 |
56 | Body
57 |
62 |
66 | Submit
67 |
68 |
72 | Delete
73 |
74 |
75 | );
76 | };
77 |
78 | export default EditEntry;
79 |
--------------------------------------------------------------------------------
/pages/admin/edit/index.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import Link from 'next/link'
3 | import axios from 'axios';
4 |
5 | const List = () => {
6 | const [entries, setEntries] = useState([]);
7 | useEffect(async () => {
8 | const res = await axios.get('/api/entries');
9 | setEntries(res.data.entriesData);
10 | }, []);
11 |
12 | return (
13 |
14 |
Entries
15 | {entries.map(entry => (
16 |
22 | ))}
23 |
24 | );
25 | };
26 |
27 | export default List;
28 |
--------------------------------------------------------------------------------
/pages/admin/post.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import dashify from 'dashify';
3 | import axios from 'axios';
4 |
5 | const Post = () => {
6 | const [content, setContent] = useState({
7 | title: undefined,
8 | body: undefined,
9 | })
10 | const onChange = (e) => {
11 | const { value, name } = e.target;
12 | setContent(prevState => ({ ...prevState, [name]: value }));
13 | }
14 | const onSubmit = async () => {
15 | const { title, body } = content;
16 | await axios.post('/api/entry', { title, slug: dashify(title), body });
17 | }
18 | return (
19 |
20 | Title
21 |
27 | Body
28 |
33 | POST
34 |
35 | );
36 | };
37 |
38 | export default Post;
39 |
--------------------------------------------------------------------------------
/pages/api/checkout_sessions/[id].ts:
--------------------------------------------------------------------------------
1 | import { NextApiRequest, NextApiResponse } from 'next'
2 |
3 | import Stripe from 'stripe'
4 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
5 | // https://github.com/stripe/stripe-node#configuration
6 | apiVersion: '2020-08-27',
7 | })
8 |
9 | export default async function handler(
10 | req: NextApiRequest,
11 | res: NextApiResponse
12 | ) {
13 | const id: string = req.query.id as string
14 | try {
15 | if (!id.startsWith('cs_')) {
16 | throw Error('Incorrect CheckoutSession ID.')
17 | }
18 | const checkout_session: Stripe.Checkout.Session =
19 | await stripe.checkout.sessions.retrieve(id, {
20 | expand: ['payment_intent'],
21 | })
22 |
23 | res.status(200).json(checkout_session)
24 | } catch (err) {
25 | const errorMessage =
26 | err instanceof Error ? err.message : 'Internal server error'
27 | res.status(500).json({ statusCode: 500, message: errorMessage })
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/pages/api/checkout_sessions/cart.ts:
--------------------------------------------------------------------------------
1 | import { NextApiRequest, NextApiResponse } from 'next'
2 |
3 | /*
4 | * Product data can be loaded from anywhere. In this case, we’re loading it from
5 | * a local JSON file, but this could also come from an async call to your
6 | * inventory management service, a database query, or some other API call.
7 | *
8 | * The important thing is that the product info is loaded from somewhere trusted
9 | * so you know the pricing information is accurate.
10 | */
11 | import { validateCartItems } from 'use-shopping-cart/utilities/serverless'
12 | import inventory from '../../../data/products'
13 |
14 | import Stripe from 'stripe'
15 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
16 | // https://github.com/stripe/stripe-node#configuration
17 | apiVersion: '2020-08-27',
18 | })
19 |
20 | export default async function handler(
21 | req: NextApiRequest,
22 | res: NextApiResponse
23 | ) {
24 | if (req.method === 'POST') {
25 | try {
26 | // Validate the cart details that were sent from the client.
27 | const line_items = validateCartItems(inventory as any, req.body)
28 | const hasSubscription = line_items.find((item) => {
29 | return !!item.price_data.recurring
30 | })
31 | // Create Checkout Sessions from body params.
32 | const params: Stripe.Checkout.SessionCreateParams = {
33 | submit_type: 'pay',
34 | payment_method_types: ['card'],
35 | billing_address_collection: 'auto',
36 | line_items,
37 | success_url: `${req.headers.origin}/thanks`,
38 | cancel_url: `${req.headers.origin}/shop`,
39 | mode: hasSubscription ? 'subscription' : 'payment',
40 | }
41 |
42 | // checkoutSession should hold the transaction ID after success!!!
43 | const checkoutSession: Stripe.Checkout.Session =
44 | await stripe.checkout.sessions.create(params)
45 |
46 | res.status(200).json(checkoutSession)
47 | // add the ID somewhere now!
48 | // perhaps to Redis?
49 | console.log(checkoutSession.id)
50 | } catch (err) {
51 | console.log(err)
52 | const errorMessage =
53 | err instanceof Error ? err.message : 'Internal server error'
54 | res.status(500).json({ statusCode: 500, message: errorMessage })
55 | }
56 | } else {
57 | res.setHeader('Allow', 'POST')
58 | res.status(405).end('Method Not Allowed')
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/pages/api/checkout_sessions/index.ts:
--------------------------------------------------------------------------------
1 | import { NextApiRequest, NextApiResponse } from 'next'
2 |
3 | import { CURRENCY, MIN_AMOUNT, MAX_AMOUNT } from '../../../config'
4 | import { formatAmountForStripe } from '../../../utils/stripe-helpers'
5 |
6 | import Stripe from 'stripe'
7 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
8 | // https://github.com/stripe/stripe-node#configuration
9 | apiVersion: '2020-08-27',
10 | })
11 |
12 | export default async function handler(
13 | req: NextApiRequest,
14 | res: NextApiResponse
15 | ) {
16 | if (req.method === 'POST') {
17 | const amount: number = req.body.amount
18 | try {
19 | // Validate the amount that was passed from the client.
20 | if (!(amount >= MIN_AMOUNT && amount <= MAX_AMOUNT)) {
21 | throw new Error('Invalid amount.')
22 | }
23 | // Create Checkout Sessions from body params.
24 | const params: Stripe.Checkout.SessionCreateParams = {
25 | submit_type: 'donate',
26 | payment_method_types: ['card'],
27 | line_items: [
28 | {
29 | name: 'Custom amount donation',
30 | amount: formatAmountForStripe(amount, CURRENCY),
31 | currency: CURRENCY,
32 | quantity: 1,
33 | },
34 | ],
35 | success_url: `${req.headers.origin}/result?session_id={CHECKOUT_SESSION_ID}`,
36 | cancel_url: `${req.headers.origin}/donate-with-checkout`,
37 | }
38 | const checkoutSession: Stripe.Checkout.Session =
39 | await stripe.checkout.sessions.create(params)
40 |
41 | res.status(200).json(checkoutSession)
42 | } catch (err) {
43 | const errorMessage =
44 | err instanceof Error ? err.message : 'Internal server error'
45 | res.status(500).json({ statusCode: 500, message: errorMessage })
46 | }
47 | } else {
48 | res.setHeader('Allow', 'POST')
49 | res.status(405).end('Method Not Allowed')
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/pages/api/payment_intents/index.ts:
--------------------------------------------------------------------------------
1 | import { NextApiRequest, NextApiResponse } from 'next'
2 |
3 | import { CURRENCY, MIN_AMOUNT, MAX_AMOUNT } from '../../../config'
4 | import { formatAmountForStripe } from '../../../utils/stripe-helpers'
5 |
6 | import Stripe from 'stripe'
7 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
8 | // https://github.com/stripe/stripe-node#configuration
9 | apiVersion: '2020-08-27',
10 | })
11 |
12 | export default async function handler(
13 | req: NextApiRequest,
14 | res: NextApiResponse
15 | ) {
16 | if (req.method !== 'POST') {
17 | res.setHeader('Allow', 'POST')
18 | res.status(405).end('Method Not Allowed')
19 | return
20 | }
21 | const {
22 | amount,
23 | payment_intent_id,
24 | }: { amount: number; payment_intent_id?: string } = req.body
25 | // Validate the amount that was passed from the client.
26 | if (!(amount >= MIN_AMOUNT && amount <= MAX_AMOUNT)) {
27 | res.status(500).json({ statusCode: 400, message: 'Invalid amount.' })
28 | return
29 | }
30 | if (payment_intent_id) {
31 | try {
32 | const current_intent = await stripe.paymentIntents.retrieve(
33 | payment_intent_id
34 | )
35 | // If PaymentIntent has been created, just update the amount.
36 | if (current_intent) {
37 | const updated_intent = await stripe.paymentIntents.update(
38 | payment_intent_id,
39 | {
40 | amount: formatAmountForStripe(amount, CURRENCY),
41 | }
42 | )
43 | res.status(200).json(updated_intent)
44 | return
45 | }
46 | } catch (e) {
47 | if ((e as any).code !== 'resource_missing') {
48 | const errorMessage =
49 | e instanceof Error ? e.message : 'Internal server error'
50 | res.status(500).json({ statusCode: 500, message: errorMessage })
51 | return
52 | }
53 | }
54 | }
55 | try {
56 | // Create PaymentIntent from body params.
57 | const params: Stripe.PaymentIntentCreateParams = {
58 | amount: formatAmountForStripe(amount, CURRENCY),
59 | currency: CURRENCY,
60 | description: process.env.STRIPE_PAYMENT_DESCRIPTION ?? '',
61 | automatic_payment_methods: {
62 | enabled: true,
63 | },
64 | }
65 | const payment_intent: Stripe.PaymentIntent =
66 | await stripe.paymentIntents.create(params)
67 |
68 | res.status(200).json(payment_intent)
69 | } catch (err) {
70 | const errorMessage =
71 | err instanceof Error ? err.message : 'Internal server error'
72 | res.status(500).json({ statusCode: 500, message: errorMessage })
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/pages/api/user.js:
--------------------------------------------------------------------------------
1 | import { db } from '../../lib/firebase';
2 |
3 | export default async function handler(req, res) {
4 | const user = await db.collection('users').doc('leerob').get();
5 |
6 | if (!user.exists) {
7 | return res.status(404).json({});
8 | }
9 |
10 | return res.status(404).json({ id: user.id, ...user.data() });
11 | }
12 |
--------------------------------------------------------------------------------
/pages/api/webhooks/index.ts:
--------------------------------------------------------------------------------
1 | import { buffer } from 'micro'
2 | import Cors from 'micro-cors'
3 | import { NextApiRequest, NextApiResponse } from 'next'
4 |
5 | import Stripe from 'stripe'
6 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
7 | // https://github.com/stripe/stripe-node#configuration
8 | apiVersion: '2020-08-27',
9 | })
10 |
11 | const webhookSecret: string = process.env.STRIPE_WEBHOOK_SECRET!
12 |
13 | // Stripe requires the raw body to construct the event.
14 | export const config = {
15 | api: {
16 | bodyParser: false,
17 | },
18 | }
19 |
20 | const cors = Cors({
21 | allowMethods: ['POST', 'HEAD'],
22 | })
23 |
24 | const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
25 | if (req.method === 'POST') {
26 | const buf = await buffer(req)
27 | const sig = req.headers['stripe-signature']!
28 |
29 | let event: Stripe.Event
30 |
31 | try {
32 | event = stripe.webhooks.constructEvent(buf.toString(), sig, webhookSecret)
33 | } catch (err) {
34 | const errorMessage = err instanceof Error ? err.message : 'Unknown error'
35 | // On error, log and return the error message.
36 | if (err! instanceof Error) console.log(err)
37 | console.log(`❌ Error message: ${errorMessage}`)
38 | res.status(400).send(`Webhook Error: ${errorMessage}`)
39 | return
40 | }
41 |
42 | // Successfully constructed event.
43 | console.log('✅ Success:', event.id)
44 |
45 | // Cast event data to Stripe object.
46 | if (event.type === 'payment_intent.succeeded') {
47 | const paymentIntent = event.data.object as Stripe.PaymentIntent
48 | console.log(`💰 PaymentIntent status: ${paymentIntent.status}`)
49 | } else if (event.type === 'payment_intent.payment_failed') {
50 | const paymentIntent = event.data.object as Stripe.PaymentIntent
51 | console.log(
52 | `❌ Payment failed: ${paymentIntent.last_payment_error?.message}`
53 | )
54 | } else if (event.type === 'charge.succeeded') {
55 | const charge = event.data.object as Stripe.Charge
56 | console.log(`💵 Charge id: ${charge.id}`)
57 | } else {
58 | console.warn(`🤷♀️ Unhandled event type: ${event.type}`)
59 | }
60 |
61 | // Return a response to acknowledge receipt of the event.
62 | res.json({ received: true })
63 | } else {
64 | res.setHeader('Allow', 'POST')
65 | res.status(405).end('Method Not Allowed')
66 | }
67 | }
68 |
69 | export default cors(webhookHandler as any)
70 |
--------------------------------------------------------------------------------
/pages/boxes.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { NextPage } from 'next'
3 | import Link from 'next/link'
4 | import Layout from '../components/Layout'
5 | import Boxes from '../components/Boxes'
6 |
7 | const BoxesPage: NextPage = () => {
8 | return (
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default BoxesPage
16 |
--------------------------------------------------------------------------------
/pages/edit.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import Link from 'next/link';
3 | import axios from 'axios';
4 |
5 | const List = () => {
6 | const [entries, setEntries] = useState([]);
7 | useEffect(async () => {
8 | const res = await axios.get('/api/entries');
9 | setEntries(res.data.entriesData);
10 | }, []);
11 |
12 | return (
13 |
14 |
Entries
15 | {entries.map(entry => (
16 |
22 | ))}
23 |
24 | );
25 | };
26 |
27 | export default List;
28 |
--------------------------------------------------------------------------------
/pages/faq.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next'
2 | import Link from 'next/link'
3 | import Layout from '../components/Layout'
4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
5 |
6 |
7 | const items = [
8 | {title: 'Workshop Priority', data: 'Get priority seats to upcoming six ArchiDAO workshops. We\'ve created educational content before!', link: true},
9 | {title: 'Scholarship', data: 'Help to make the difference in the democratisation of Architecture Technology.'},
10 | {title: 'Exhibition', data: 'Opportunity to show your work in ArchiDAO Gallery and Exhibitions.'},
11 | {title: 'Fund Tutors', data: 'Sponsor instructors for next six workshops and make them accessible to holders for free.'},
12 | {title: 'Bonus Hours', data: 'Bonus after hours with tutors for the six upcoming workshops.'},
13 | {title: 'Voting', data: 'Eligible to vote for future governance of educational initiatives.'},
14 | ]
15 |
16 | const IndexPage: NextPage = () => {var i = 0
17 | return (
18 |
19 |
20 |
Why is your NFT not just a hype?
21 |
ArchiDAO presents our wearable NFT! The wearable will be available for use in Decentraland.
22 | Cherry on the top, our NFT has six additional utilities.
23 |
24 |
What are the six utilities?
25 |
26 |
27 | {items.map((item) => {i += 1; if (item.link == true) {
28 | return(
29 |
30 |
35 |
36 | )} else {return(
37 |
38 |
39 |
{i}. {item.title}
40 |
{item.data}
41 |
42 |
43 | )}
44 | })}
45 |
46 |
47 |
48 | )
49 | }
50 |
51 | export default IndexPage
52 |
--------------------------------------------------------------------------------
/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next'
2 | import Link from 'next/link'
3 | import Layout from '../components/Layout'
4 |
5 | const IndexPage: NextPage = () => {
6 | return (
7 |
8 |
17 |
18 | )
19 | }
20 |
21 | export default IndexPage
22 |
--------------------------------------------------------------------------------
/pages/post.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import dashify from 'dashify';
3 | import axios from 'axios';
4 |
5 | const Post = () => {
6 | const [content, setContent] = useState({
7 | title: undefined,
8 | body: undefined,
9 | })
10 | const onChange = (e) => {
11 | const { value, name } = e.target;
12 | setContent(prevState => ({ ...prevState, [name]: value }));
13 | }
14 | const onSubmit = async () => {
15 | const { title, body } = content;
16 | await axios.post('/api/entry', { title, slug: dashify(title), body });
17 | }
18 | return (
19 |
20 | Title
21 |
27 | Body
28 |
33 | POST
34 |
35 | );
36 | };
37 |
38 | export default Post;
39 |
--------------------------------------------------------------------------------
/pages/result.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next'
2 | import { useRouter } from 'next/router'
3 |
4 | import Layout from '../components/Layout'
5 | import PrintObject from '../components/PrintObject'
6 | import Cart from '../components/Cart'
7 | import ClearCart from '../components/ClearCart'
8 |
9 | import { fetchGetJSON } from '../utils/api-helpers'
10 | import useSWR from 'swr'
11 |
12 | const ResultPage: NextPage = () => {
13 | const router = useRouter()
14 |
15 | // Fetch CheckoutSession from static page via
16 | // https://nextjs.org/docs/basic-features/data-fetching#static-generation
17 | const { data, error } = useSWR(
18 | router.query.session_id
19 | ? `/api/checkout_sessions/${router.query.session_id}`
20 | : null,
21 | fetchGetJSON
22 | )
23 |
24 | if (error) return failed to load
25 |
26 | return (
27 |
28 |
29 |
Checkout Payment Result
30 |
Status: {data?.payment_intent?.status ?? 'loading...'}
31 |
CheckoutSession response:
32 |
33 |
34 |
35 |
36 |
37 |
38 | )
39 | }
40 |
41 | export default ResultPage
42 |
--------------------------------------------------------------------------------
/pages/shop.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next'
2 | import Layout from '../components/Layout'
3 | import React from "react"
4 | import Cart from '../components/Cart'
5 | import CartSummary from '../components/CartSummary'
6 | import Products from '../components/Products'
7 | import { AddressContext } from "../contexts/Address"
8 | const DonatePage: NextPage = () => {
9 |
10 | return (
11 |
12 |
13 |
19 |
20 | )
21 | }
22 |
23 | export default DonatePage
24 |
--------------------------------------------------------------------------------
/pages/thanks.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import { NextPage } from 'next'
3 | import Link from 'next/link'
4 | import Layout from '../components/Layout'
5 | import Head from "next/head";
6 | import { CWload } from '../components/CWload';
7 |
8 | import { setDoc,doc,collection, getFirestore } from '@firebase/firestore';
9 |
10 | import { useState } from 'react';
11 | import { firestore } from '../components/firebase/client';
12 |
13 | import React from "react"
14 |
15 | import {
16 | useNetwork,
17 | useAddress,
18 | } from '@thirdweb-dev/react';
19 |
20 |
21 | const addPurchasex = async (address) => {
22 | // alert(String(address))
23 | };
24 |
25 | const IndexPage: NextPage = () => {
26 | CWload('CWload')
27 | return (
28 |
29 |
30 |
31 | Thanks for purchasing!
32 | The ArchiDAO NFT will be distributed in the next 48 hours.
33 | If the address shown at top right is not correct, please hit us up in Discord!
34 |
35 |
36 |
37 |
38 | )
39 |
40 | }
41 |
42 | export default IndexPage
43 |
44 |
45 | // addPurchasex()}
48 | // >
49 | //
50 | // Click to pre-Mint
51 | //
52 |
--------------------------------------------------------------------------------
/pages/web3.xjs:
--------------------------------------------------------------------------------
1 | import {
2 | useNetwork,
3 | useAddress,
4 | } from '@thirdweb-dev/react';
5 |
6 | function delay(time) {
7 | return new Promise(resolve => setTimeout(resolve, time));
8 | }
9 | export default async function () {
10 | var addressX = await useAddress()
11 | return (addressX)
12 | }
13 |
--------------------------------------------------------------------------------
/pages/whitelist-thanks.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from 'next'
2 | import Link from 'next/link'
3 | import Layout from '../components/Layout'
4 |
5 | const IndexPage: NextPage = () => {
6 | return (
7 |
8 |
18 |
19 | )
20 | }
21 |
22 | export default IndexPage
23 |
--------------------------------------------------------------------------------
/pages/whitelist.tsx:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import { NextPage } from 'next'
3 | import Link from 'next/link'
4 | import Layout from '../components/Layout'
5 | import Head from "next/head";
6 | import { CWload } from '../components/CWload';
7 | import { useRouter } from 'next/router'
8 | import { useState } from 'react';
9 | import React from "react"
10 |
11 | import { setDoc,doc,collection, getFirestore,updateDoc, arrayUnion } from '@firebase/firestore';
12 | import { firestore } from '../components/firebase/client';
13 |
14 |
15 | import {
16 | useNetwork,
17 | useAddress,
18 | } from '@thirdweb-dev/react';
19 |
20 |
21 | const addPurchasex = async (address) => {
22 | // alert(String(address))
23 | };
24 |
25 | const IndexPage: NextPage = () => {
26 | const [values, setValues] = useState({
27 | email: '',
28 | });
29 | const handleEmailInputChange = (event) => {
30 | event.persist();
31 | values.email = event.target.value
32 | setValues((values) => ({
33 | ...values,
34 | email: event.target.value,
35 | }));
36 | };
37 |
38 |
39 | var address = CWload('whitelist')
40 | // Handles the submit event on form submit.
41 | const handleSubmit = async (event) => {
42 | // Stop the form from submitting and refreshing the page.
43 | event.preventDefault()
44 | const timestamp = Date.now().toString();
45 | console.log(address)
46 | console.log(timestamp)
47 | await updateDoc(doc(firestore, "whitelist", String(address)), {
48 | email: (String(values.email)) }).catch(()=>{ setDoc(doc(firestore, "whitelist", String(address)), {
49 | email: (String(values.email)) });})
50 | await updateDoc(doc(firestore, "crypto_logins", String(address)), {
51 | whitelist: arrayUnion(String(timestamp)), email: arrayUnion(String(values.email)) }).catch(()=>{ setDoc(doc(firestore, "crypto_logins", String(address)), {
52 | whitelist: (String(timestamp)), email: (String(values.email)) });})
53 |
54 |
55 |
56 | window.location.href = "/whitelist-thanks";
57 | // Send the form data to our forms API on Vercel and get a response.
58 | }
59 | if (address) { return (
60 |
61 |
62 |
66 |
67 |
68 | )} else
69 | { return (
70 |
71 |
72 |
Please connect wallet to whitelist
73 |
74 |
75 | )}
76 |
77 | }
78 |
79 |
80 |
81 | export default IndexPage
82 |
83 |
84 | // addPurchasex()}
87 | // >
88 | //
89 | // Click to pre-Mint
90 | //
91 |
--------------------------------------------------------------------------------
/public/Archidao_wearable.js:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | */
4 |
5 | import React, { useRef } from 'react'
6 | import { useGLTF } from '@react-three/drei'
7 |
8 | export default function Model({ ...props }) {
9 | const group = useRef()
10 | const { nodes, materials } = useGLTF('/archidao_wearable.gltf')
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
22 | useGLTF.preload('/archidao_wearable.gltf')
23 |
--------------------------------------------------------------------------------
/public/Test.js:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | */
4 |
5 | import React, { useRef } from 'react'
6 | import { useGLTF } from '@react-three/drei'
7 |
8 | export default function Model({ ...props }) {
9 | const group = useRef()
10 | const { nodes, materials } = useGLTF('/archidao_wearable_2.gltf')
11 | return (
12 |
13 |
14 |
15 | )
16 | }
17 |
18 | useGLTF.preload('/test.gltf')
19 |
--------------------------------------------------------------------------------
/public/archidao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/archidao.png
--------------------------------------------------------------------------------
/public/archidao_wearable.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/archidao_wearable.bin
--------------------------------------------------------------------------------
/public/archidao_wearable.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/archidao_wearable.glb
--------------------------------------------------------------------------------
/public/black_ready.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/black_ready.jpg
--------------------------------------------------------------------------------
/public/checkout-one-time-payments.svg:
--------------------------------------------------------------------------------
1 | $29.90 Pay $29.90 4242 11/26 934 Jenny Rosen jenny@rosen.com
--------------------------------------------------------------------------------
/public/checkout_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/checkout_demo.gif
--------------------------------------------------------------------------------
/public/draw-with-compass.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/public/elements-card-payment.svg:
--------------------------------------------------------------------------------
1 | Pay $29.90 4242 4242 4242 4242
--------------------------------------------------------------------------------
/public/elements_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/elements_demo.gif
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/logo.png
--------------------------------------------------------------------------------
/public/male_2.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/male_2.glb
--------------------------------------------------------------------------------
/public/nft_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/nft_.png
--------------------------------------------------------------------------------
/public/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/preview.png
--------------------------------------------------------------------------------
/public/shopping_cart_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/shopping_cart_demo.gif
--------------------------------------------------------------------------------
/public/social_card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/social_card.png
--------------------------------------------------------------------------------
/public/use-shopping-cart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/public/use-shopping-cart.png
--------------------------------------------------------------------------------
/store/context.js:
--------------------------------------------------------------------------------
1 | import { createContext } from "react";
2 |
3 | const Context = createContext({});
4 |
5 | export default Context;
6 |
--------------------------------------------------------------------------------
/store/globalStateProvider.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import useGlobalState from "./useGlobalState";
3 | import Context from "./context";
4 |
5 | const GlobalStateProvider = ({ children }) => {
6 | return (
7 | {children}
8 | );
9 | };
10 |
11 | export default GlobalStateProvider;
12 |
--------------------------------------------------------------------------------
/store/useGlobalState.js:
--------------------------------------------------------------------------------
1 | import { useReducer } from "react";
2 |
3 | const reducer = (state, action) => {
4 | switch (action.type) {
5 | case "LOGIN":
6 | return {
7 | ...state,
8 | isLoggedIn: true,
9 | };
10 | case "LOGOUT":
11 | return {
12 | ...state,
13 | isLoggedIn: false
14 | };
15 | default: {
16 | return state;
17 | }
18 | }
19 | };
20 |
21 | const useGlobalState = () => {
22 | const [globalState, globalDispatch] = useReducer(reducer, {
23 | isLoggedIn: false,
24 | active: false,
25 | address: ''
26 | });
27 |
28 | return { globalState, globalDispatch };
29 | };
30 |
31 | export default useGlobalState;
32 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | @import url("https://rsms.me/inter/inter.css");
2 | /* @import url("https://fonts.googleapis.com/css2?family=Antonio:wght@600&display=swap"); */
3 | @import url('https://fonts.googleapis.com/css2?family=Major+Mono+Display&display=swap');
4 | @import url('https://fonts.googleapis.com/css2?family=Bungee+Hairline&display=swap');
5 | * {
6 | box-sizing: border-box;
7 | }
8 |
9 | html,
10 | body,
11 | #root {
12 | width: 100%;
13 | min-height: 100vh;
14 | margin: 0;
15 | padding: 0;
16 | background: linear-gradient(180deg, #200020 0%, #151015 90%);
17 | font-family: 'Major Mono Display', monospace;
18 | }
19 |
20 | body {
21 | font-family: "Inter var", sans-serif;
22 | cursor: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTMwLjUgMTZDMzAuNSAyNC4wMDgxIDI0LjAwODEgMzAuNSAxNiAzMC41QzcuOTkxODcgMzAuNSAxLjUgMjQuMDA4MSAxLjUgMTZDMS41IDcuOTkxODcgNy45OTE4NyAxLjUgMTYgMS41QzI0LjAwODEgMS41IDMwLjUgNy45OTE4NyAzMC41IDE2WiIgc3Ryb2tlPSJibGFjayIvPgo8cGF0aCBkPSJNNiA5QzcuNjU2ODUgOSA5IDcuNjU2ODUgOSA2QzkgNC4zNDMxNSA3LjY1Njg1IDMgNiAzQzQuMzQzMTUgMyAzIDQuMzQzMTUgMyA2QzMgNy42NTY4NSA0LjM0MzE1IDkgNiA5WiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg=="),
23 | auto;
24 | }
25 |
26 |
27 | @media screen and (max-width: 568px) {
28 | .full {
29 | visibility: hidden;
30 | display: none;
31 | }
32 | }
33 |
34 | /* Variables */
35 | :root {
36 | --body-color: black;
37 | --checkout-color: #ffffff;
38 | --checkout-color2: #500050;
39 | --elements-color: #6772e5;
40 | --body-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
41 | sans-serif;
42 | --h1-color: #ff1fff;
43 | --h2-color: #ff81ff;
44 | --h3-color: #ffacff;
45 | --href-color: #20ffff;
46 | --radius: 6px;
47 | --container-width-max: 1280px;
48 | --page-width-max: 600px;
49 | --transition-duration: 2s;
50 | }
51 | /* canvas{
52 | position: absolute;
53 | z-index: 99 !important;
54 | left: 0;
55 | top: 0;
56 | width: 100vw !important;
57 | height: 100vh !important;
58 | } */
59 |
60 | .header-content {
61 | position: fixed;
62 | border-radius: 0 0 20px 20px;
63 | height: min(8vw,100px);
64 | max-height: 120px;
65 | width: 100vw;
66 | left: 0;
67 | top: 0;
68 | color: white;
69 | /* padding: 1vw; */
70 | background: var(--body-color);
71 | opacity: 90%;
72 | font-family: 'Major Mono Display', monospace;
73 | font-size: min(2vw,20px);
74 | }
75 | .faq-item{
76 | display: block;
77 | border-style: solid;
78 | border-radius: 10px;
79 | border-width: 1.25px;
80 | border-color: #909090;
81 | color: white!important;
82 | width: 100%;
83 | max-width: 65vh;
84 | margin: 0 20px 20px 0;
85 | font-weight: bold;
86 | text-decoration: none;
87 | box-shadow: 0 0 10px #abffad, 0 0 5px #00ff50;
88 | z-index: 99;
89 | padding: 10px;
90 | line-height: normal!important;
91 | }
92 | .cw-button{
93 | border-style: solid;
94 | border-width: 1.25px;
95 | border-color: #90ff90;
96 | width: auto;
97 | /* height: 6vw; */
98 | color: white;
99 | background-color: black;
100 | position: relative;
101 | float: right;
102 | padding: 1vw;
103 | right: 5px;
104 | top: 5px;
105 | margin: .25vw;
106 | line-height: min(3vw,20px);
107 | }
108 | .backdrop{
109 | position: fixed;
110 | z-index: 0;
111 | width: 100vw !important;
112 | height: 100vh !important;
113 | }
114 | body {
115 | margin: 0;
116 | padding: 0;
117 | background: var(--body-color);
118 | overflow-y: scroll;
119 | color:var(--h3-color);
120 | }
121 |
122 | * {
123 | /* box-sizing: border-box; */
124 | font-family: 'Bungee Hairline', cursive;
125 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
126 | }
127 | .faq-div{
128 | width: 100%;
129 | /* background-color: red; */
130 | display: block;
131 | border-style: solid;
132 | border-radius: 10px;
133 | border-width: 1.25px;
134 | border-color: #909090;
135 | color: white!important;
136 | width: 100%;
137 | max-width: 65vh;
138 | margin: 0 20px 20px 0;
139 | font-weight: bold;
140 | text-decoration: none;
141 | background-color: #00000090;
142 | box-shadow: 0 0 20px #abffad, 0 0 10px #00ff50;
143 | z-index: 99;
144 | padding: 10px;
145 | line-height: normal!important;
146 | }
147 | .shop-info {
148 | margin: 20px;
149 | display: inline;
150 |
151 | /* padding: 5vw; */
152 | }
153 | .shop-info-div {
154 | /* display: inline; */
155 | margin: 10px 0 20px 0 ;
156 | /* text-align: center; */
157 | display: block;
158 | height: 60px;
159 | /* background-color: blue */
160 |
161 | }
162 | .shop-sum-div{
163 | /* display: flex; */
164 | width: 100%;
165 | /* padding: 10px; */
166 | /* background-color: red */
167 | }
168 | .cart-button{
169 | display: block;
170 | width: 95%;
171 | left: 0;
172 | margin-top: 0;
173 | margin-bottom: 0;
174 | }
175 | html {
176 | overflow: scroll;
177 | }
178 | ::-webkit-scrollbar {
179 | width: 0px;
180 | background: transparent; /* make scrollbar transparent */
181 | }
182 | .cart-button-top{
183 | border-radius: 10px 10px 0 0!important;
184 | }
185 | .cart-button-mid{
186 | border-radius: 0 0 0 0!important;
187 | }
188 | .cart-button-bot{
189 | border-radius: 0 0 10px 10px !important;
190 | margin-bottom: 30px;
191 | }
192 |
193 | .spanx {
194 | white-space: nowrap;
195 | overflow: hidden;
196 | /* text-overflow: ellipsis; */
197 | /* display: inline !important; */
198 | }
199 | .shop-button-div {
200 |
201 | /* display: grid; */
202 |
203 | /* padding: 20px; */
204 | /* background-color: yellow; */
205 | }
206 |
207 | .add-button{
208 | border-radius: 0px 10px 10px 0!important;
209 |
210 | }
211 | .subtract-button{
212 | border-radius: 10px 0px 0 10px!important;
213 | }
214 | .change-count-button{
215 | width: 45%;
216 | margin: 10px 00px 10px 00px ;
217 | }
218 | .clear-cart-background {
219 | background-color: #50000050!important;
220 | }
221 | #__next {
222 | display: flex;
223 | justify-content: center;
224 | }
225 |
226 | .container {
227 | max-width: var(--container-width-max);
228 | padding: 45px 25px;
229 | display: absolute;
230 | flex-direction: row;
231 | z-index: 99;
232 | padding-top: 12vh;
233 | }
234 |
235 | .page-container {
236 | padding-bottom: 60px;
237 | max-width: var(--page-width-max);
238 | }
239 |
240 | h1 {
241 | font-weight: 600;
242 | color: var(--h1-color);
243 | margin: 6px 0 12px;
244 | font-size: 27px;
245 | line-height: 32px;
246 | }
247 |
248 | h1 span.light {
249 | color: var(--h3-color);
250 | }
251 |
252 | h2 {
253 | color: var(--h2-color);
254 | margin: 8px 0;
255 | }
256 |
257 | h3 {
258 | font-size: 17px;
259 | color: var(--h3-color);
260 | margin: 8px 0;
261 | }
262 |
263 | .faq-a {
264 | color: var(--href-color);
265 | text-decoration: underline;
266 | }
267 |
268 | a {
269 | color: var(--checkout-color);
270 | text-decoration: none;
271 | }
272 |
273 |
274 | .nft-container{
275 | max-width: 500px;
276 | min-width: 50vh;
277 | padding: 1vw;
278 | justify-content: center;
279 | align-items: center;
280 | text-align: center;
281 | margin-top: min(5vw,100px);
282 | margin-bottom: 100vh;
283 | background: #00000090;
284 | border-radius: 20px;
285 | border-style: solid;
286 | border-width: 1.25px;
287 | border-color: #909090;
288 | }
289 |
290 | .header-logo img {
291 | height: min(6vw,80px);
292 | }
293 | .header-logo{
294 | color: black;
295 | font-size: min(3vw,40px);
296 | color: white;
297 | font-weight: 600;
298 | /* position: fixed; */
299 | float: left;
300 | padding: 1vw;
301 | margin: 1vw;
302 | margin-top: -1vw;
303 | }
304 |
305 |
306 | ul,
307 | li {
308 | list-style: none;
309 | padding: 0;
310 | margin: 0;
311 | }
312 |
313 | .card-list {
314 | display: flex;
315 | flex-wrap: wrap;
316 | align-content: flex-start;
317 | padding-top: 64px;
318 | }
319 |
320 | .card {
321 | display: block;
322 | border-style: solid;
323 | border-radius: 10px;
324 | border-width: 1.25px;
325 | border-color: #909090;
326 | position: relative;
327 | /* padding: 12px; */
328 | height: min(400px,100vw);
329 | width: min(400px, 100vw);
330 | flex: 0 0 33%;
331 | min-width: 304px;
332 | width: 33%;
333 | margin: 0 20px 20px 0;
334 | text-decoration: none;
335 | box-shadow: 0 0 160px #abffad, 0 0 60px #00ff50;
336 | z-index: 99;
337 | }
338 | .card2 {
339 | display: block;
340 | border-style: solid;
341 | border-radius: 10px;
342 | border-width: 1.25px;
343 | border-color: #909090;
344 | position: relative;
345 | /* padding: 12px; */
346 | /* height: min(400px,100vw);
347 | width: min(400px, 100vw); */
348 | flex: 0 0 33%;
349 | left: 33%;
350 | /* min-width: 304px; */
351 | /* width: 33%; */
352 | margin: 20px;
353 | padding: 10px;
354 | text-decoration: none;
355 | box-shadow: 0 0 160px #abffad, 0 0 60px #00ff50;
356 | z-index: 99;
357 | }
358 | .card h2 {
359 | color: #fff;
360 | margin: 10px;
361 | }
362 | .card h2.bottom {
363 | position: absolute;
364 | bottom: 10px;
365 | }
366 |
367 | .card img {
368 | width: 90%;
369 | margin: 5%;
370 | position: absolute;
371 | border-radius: 20px;
372 | box-shadow: 0 0 20px #50ff80, 0 0 10px #00ffff;
373 | /* top: 50%;
374 | left: 50%;
375 | transform: translate(-50%, -50%); */
376 | }
377 |
378 | .error-message {
379 | color: #ef2961;
380 | }
381 |
382 | .FormRow,
383 | fieldset,
384 | input[type='number'],
385 | input[type='text'] {
386 | border-radius: var(--radius);
387 | padding: 5px 12px;
388 | width: 100%;
389 | background: #fff;
390 | appearance: none;
391 | font-size: 16px;
392 | margin-top: 10px;
393 | }
394 |
395 | input[type='range'] {
396 | margin: 5px 0;
397 | width: 100%;
398 | }
399 |
400 | button {
401 | border-radius: var(--radius);
402 |
403 | font-size: larger;
404 | /* border: 0; */
405 | /* padding: 12px 16px; */
406 | /* margin-top: 10px; */
407 | margin: 10px;
408 | font-weight: 600;
409 | cursor: pointer;
410 | transition: all 0.2s ease;
411 | /* display: block; */
412 | /* width: 100%; */
413 | /* z-index: 99; */
414 | /* color: var(--h3-color); */
415 | /* border: 1px solid var(--elements-color); */
416 | /* background: var(--elements-color); */
417 | /* transition: box-shadow var(--transition-duration); */
418 | }
419 | .shop-button {
420 | border-radius: var(--radius);
421 | color: white;
422 | font-size: larger;
423 | border: 0;
424 | /* padding: 12px 16px; */
425 | /* margin: 10px 00px 10px 00px ; */
426 | /* margin-top: 10px; */
427 | font-weight: 600;
428 | cursor: pointer;
429 | transition: all 0.2s ease;
430 | /* display: flex; */
431 | /* min-width: 16vw; */
432 | /* width: auto; */
433 | z-index: 99;
434 | border: 1px solid var(--elements-color);
435 | color: var(--h3-color);
436 | background: var(--elements-color);
437 | transition: box-shadow var(--transition-duration);
438 | min-width: 60px;
439 | min-height: 60px;
440 |
441 | }
442 | button:disabled {
443 | opacity: 0.5;
444 | cursor: not-allowed;
445 | }
446 | form{
447 | min-width: min(100vw,400px) ;
448 | display:flex;
449 | }
450 |
451 | .elements-style {
452 | color: var(--elements-color);
453 | border: 1px solid var(--elements-color);
454 | }
455 | .elements-style-background {
456 | background: var(--elements-color);
457 | transition: box-shadow var(--transition-duration);
458 | }
459 | .card.elements-style-background:hover {
460 | box-shadow: 20px 20px 60px #464e9c, -20px -20px 60px #8896ff;
461 | }
462 | .checkout-style {
463 | color: var(--checkout-color);
464 | border: 1px solid var(--checkout-color);
465 | }
466 | .checkout-style-background {
467 | background: var(--checkout-color);
468 | transition: box-shadow var(--transition-duration);
469 | }
470 | .card.checkout-style-background:hover {
471 | box-shadow: 20px 20px 60px #614b91, -20px -20px 60px #bd91ff;
472 | }
473 | .cart-style-background {
474 | background: #00000090;
475 | transition: box-shadow var(--transition-duration);
476 | }
477 | .card.cart-style-background:hover {
478 | box-shadow: 20px 20px 60px teal, -20px -20px 60px teal;
479 | }
480 |
481 | /* Products */
482 | .products {
483 | display: grid;
484 | /* gap: 1rem; */
485 | /* grid-template-columns: repeat(2, 1fr); */
486 | margin-top: 1rem;
487 | }
488 | .nftimage{
489 | display: flex;
490 | justify-content: center;
491 | align-items: center;
492 | width: 80%;
493 | margin: 10%;
494 | }
495 | .product img {
496 | /* max-width: 100%; */
497 |
498 | /* margin: 30px; */
499 | border-radius: 20px;
500 | box-shadow: 0 0 40px #50ff80, 0 0 20px #00ffff;
501 | text-align: center;
502 | align-items: center;
503 |
504 | /* margin: 60px; */
505 | }
506 | .whitelist-div {
507 | display: flex;
508 |
509 | background: #00000090;
510 | border-style: solid;
511 | border-radius: 10px;
512 | border-width: 1.25px;
513 | border-color: #909090;
514 | color: white!important;
515 | width: 100%;
516 | /* max-width: 65vh; */
517 | /* margin: 0 20px 20px 0; */
518 | margin: 10px;
519 | padding: 10px;
520 | font-weight: bold;
521 | text-decoration: none;
522 | box-shadow: 0 0 10px #abffad, 0 0 5px #00ff50;
523 | z-index: 99;
524 | margin-top: min(15vh,100px);
525 | line-height: normal!important;
526 | }
527 | .product{
528 | display: inline !important;
529 | white-space: nowrap !important;
530 | overflow: hidden !important;
531 | text-overflow: ellipsis !important;
532 | }
533 |
534 | /* Test card number */
535 | .test-card-notice {
536 | display: block;
537 | margin-block-start: 1em;
538 | margin-block-end: 1em;
539 | margin-inline-start: 0px;
540 | margin-inline-end: 0px;
541 | }
542 | .card-number {
543 | display: inline;
544 | white-space: nowrap;
545 | font-family: Menlo, Consolas, monospace;
546 | color: #3c4257;
547 | font-weight: 500;
548 | }
549 | .card-number span {
550 | /* display: inline-block; */
551 | width: 4px;
552 | }
553 |
554 | /* Code block */
555 | code,
556 | pre {
557 | font-family: 'SF Mono', 'IBM Plex Mono', 'Menlo', monospace;
558 | font-size: 12px;
559 | background: rgba(0, 0, 0, 0.03);
560 | padding: 12px;
561 | border-radius: var(--radius);
562 | max-height: 500px;
563 | width: var(--page-width-max);
564 | overflow: auto;
565 | }
566 |
567 | .banner {
568 | /* max-width: 825px; */
569 |
570 | width: auto;
571 | /* margin: 0 auto; */
572 | font-size: min(3vw,20px);
573 | background: var(--body-color);
574 | font-weight: 600;
575 | opacity: 90%;
576 | color: #6a7c94;
577 | border-radius: 50px 0 0px 0px;
578 | /* box-shadow: -10px 10px 20px #20ff50, 10px -10px 20px #002010; */
579 | display: flex;
580 | align-items: right;
581 | box-sizing: border-box;
582 | padding: 15px;
583 | line-height: 1.15;
584 | position: fixed;
585 | bottom: 0;
586 | left: 0;
587 | right: 0;
588 | text-align: right;
589 | justify-content: right;
590 | z-index: 99;
591 | }
592 | .whitelist-submit{
593 | width: auto;
594 | right: 10px;
595 | margin: 10px!important;
596 | padding: 10px!important;
597 | position: relative;
598 | display: block;
599 | font-size: 1rem!important;
600 | }
601 | .whitelist-form{
602 | width: 100%;
603 | }
604 | .whitelist-input{
605 | width: 80%!important;
606 | margin: 10px!important;
607 | }
608 |
609 | @media only screen and (max-width: 980px) {
610 | .container {
611 | flex-direction: column;
612 | padding-top: 12vh;
613 | }
614 |
615 |
616 |
617 | .card {
618 | margin: 0 20px 20px 0;
619 | box-shadow: none;
620 | }
621 |
622 | .card-list {
623 | padding-top: 12vh;
624 | }
625 |
626 | .banner {
627 | box-shadow: none;
628 | bottom: 0;
629 | }
630 | .faq-div {
631 | width: 100vw;
632 | margin: 10px;
633 | }
634 | }
635 |
636 | @media only screen and (max-width: 600px) {
637 | .container {
638 | flex-direction: column;
639 | padding-top: 12vh;
640 | }
641 |
642 | .card {
643 | display: block;
644 | border-radius: 8px;
645 | /* flex: 0 0 100%; */
646 | /* max-width: 100%; */
647 | padding-left: 0;
648 | padding-right: 0;
649 | margin: 20px;
650 | box-shadow: none;
651 | }
652 |
653 | .faq-div {
654 | width: 100vw;
655 | }
656 | .whitelist-div{
657 | width: 100vw;
658 | }
659 | .card-list {
660 | padding-top: 12vh;
661 | }
662 |
663 | code,
664 | pre,
665 | h3 {
666 | display: none;
667 | }
668 |
669 | .banner {
670 | box-shadow: none;
671 | bottom: 0;
672 | }
673 | }
674 |
--------------------------------------------------------------------------------
/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .scene{
2 | width:100vw;
3 | height:100vh;
4 | }
5 |
6 | .canvas{
7 | background: #000;
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2019",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "allowSyntheticDefaultImports": true,
15 | "isolatedModules": true,
16 | "incremental": true,
17 | "jsx": "preserve"
18 | },
19 | "exclude": ["node_modules"],
20 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
21 | }
22 |
--------------------------------------------------------------------------------
/utils/api-helpers.ts:
--------------------------------------------------------------------------------
1 | export async function fetchGetJSON(url: string) {
2 | try {
3 | const data = await fetch(url).then((res) => res.json())
4 | return data
5 | } catch (err) {
6 | if (err instanceof Error) {
7 | throw new Error(err.message)
8 | }
9 | throw err
10 | }
11 | }
12 |
13 | export async function fetchPostJSON(url: string, data?: {}) {
14 | try {
15 | // Default options are marked with *
16 | const response = await fetch(url, {
17 | method: 'POST', // *GET, POST, PUT, DELETE, etc.
18 | mode: 'cors', // no-cors, *cors, same-origin
19 | cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
20 | credentials: 'same-origin', // include, *same-origin, omit
21 | headers: {
22 | 'Content-Type': 'application/json',
23 | // 'Content-Type': 'application/x-www-form-urlencoded',
24 | },
25 | redirect: 'follow', // manual, *follow, error
26 | referrerPolicy: 'no-referrer', // no-referrer, *client
27 | body: JSON.stringify(data || {}), // body data type must match "Content-Type" header
28 | })
29 | return await response.json() // parses JSON response into native JavaScript objects
30 | } catch (err) {
31 | if (err instanceof Error) {
32 | throw new Error(err.message)
33 | }
34 | throw err
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/utils/get-stripejs.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is a singleton to ensure we only instantiate Stripe once.
3 | */
4 | import { Stripe, loadStripe } from '@stripe/stripe-js'
5 |
6 | let stripePromise: Promise
7 | const getStripe = () => {
8 | if (!stripePromise) {
9 | stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!)
10 | }
11 | return stripePromise
12 | }
13 |
14 | export default getStripe
15 |
--------------------------------------------------------------------------------
/utils/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/utils/index.js
--------------------------------------------------------------------------------
/utils/stripe-helpers.ts:
--------------------------------------------------------------------------------
1 | export function formatAmountForDisplay(
2 | amount: number,
3 | currency: string
4 | ): string {
5 | let numberFormat = new Intl.NumberFormat(['en-US'], {
6 | style: 'currency',
7 | currency: currency,
8 | currencyDisplay: 'symbol',
9 | })
10 | return numberFormat.format(amount)
11 | }
12 |
13 | export function formatAmountForStripe(
14 | amount: number,
15 | currency: string
16 | ): number {
17 | let numberFormat = new Intl.NumberFormat(['en-US'], {
18 | style: 'currency',
19 | currency: currency,
20 | currencyDisplay: 'symbol',
21 | })
22 | const parts = numberFormat.formatToParts(amount)
23 | let zeroDecimalCurrency: boolean = true
24 | for (let part of parts) {
25 | if (part.type === 'decimal') {
26 | zeroDecimalCurrency = false
27 | }
28 | }
29 | return zeroDecimalCurrency ? amount : Math.round(amount * 100)
30 | }
31 |
32 | export function formatAmountFromStripe(
33 | amount: number,
34 | currency: string
35 | ): number {
36 | let numberFormat = new Intl.NumberFormat(['en-US'], {
37 | style: 'currency',
38 | currency: currency,
39 | currencyDisplay: 'symbol',
40 | })
41 | const parts = numberFormat.formatToParts(amount)
42 | let zeroDecimalCurrency: boolean = true
43 | for (let part of parts) {
44 | if (part.type === 'decimal') {
45 | zeroDecimalCurrency = false
46 | }
47 | }
48 | return zeroDecimalCurrency ? amount : Math.round(amount / 100)
49 | }
50 |
--------------------------------------------------------------------------------
/with-stripe-typescript-app.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/blixor/next-three-stripe-web3/6fd4189648eb3dd064090a24f99b10a8e9de0643/with-stripe-typescript-app.zip
--------------------------------------------------------------------------------