├── .github └── workflows │ ├── deploy.yml │ └── npmpublish.yml ├── .gitignore ├── README.md ├── assets ├── banner.ai ├── example-patients-fail.ai ├── example-patients.ai ├── homepage.ai ├── icons │ ├── github-white.ai │ ├── mit-icon.ai │ ├── npm-white.ai │ ├── otel-icon.ai │ ├── rocketconnect-icon.ai │ ├── rocketconnect.ai │ └── typescript-icon.ai └── logo.ai ├── graphql-otel.com ├── .env.example ├── nginx.nginx ├── package-lock.json ├── package.json ├── postcss.config.cjs ├── public │ ├── banner.png │ ├── code.svg │ ├── example-patients-fail.svg │ ├── example-patients.svg │ ├── favicon.svg │ ├── fonts │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Italic.ttf │ │ └── Roboto-Regular.ttf │ ├── github-white.svg │ ├── logo.svg │ ├── mit-icon.png │ ├── mit-icon.svg │ ├── npm-white.svg │ ├── otel-icon.svg │ ├── rocket-connect.png │ ├── rocket-connect.svg │ └── typescript-icon.svg ├── server.js ├── src │ ├── App.tsx │ ├── components │ │ ├── Contact.tsx │ │ ├── Container.tsx │ │ ├── Footer.tsx │ │ ├── GettingStarted.tsx │ │ ├── Header.tsx │ │ ├── Intro.tsx │ │ └── Supported.tsx │ ├── config.ts │ ├── images.tsx │ ├── index.css │ ├── index.html │ └── index.tsx ├── tailwind.config.cjs ├── tsconfig.json └── webpack.config.cjs └── package ├── .npmignore ├── package-lock.json ├── package.json ├── src └── index.ts └── tsconfig.json /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Publish Website 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: SSH and deploy node app 12 | uses: appleboy/ssh-action@master 13 | with: 14 | host: ${{ secrets.SSH_HOST }} 15 | username: ${{ secrets.SSH_USERNAME }} 16 | key: ${{ secrets.SSH_KEY }} 17 | script: | 18 | export NVM_DIR=~/.nvm 19 | source ~/.nvm/nvm.sh 20 | cd graphql-otel 21 | git reset --hard 22 | git checkout main 23 | git fetch && git pull 24 | cd graphql-otel.com 25 | npm install 26 | npm run build 27 | NODE_ENV=production pm2 restart graphql-otel.com 28 | -------------------------------------------------------------------------------- /.github/workflows/npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: Test, Build, Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | publish-npm: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: 18 16 | registry-url: https://registry.npmjs.org/ 17 | - run: cp ./README.md ./package/README.md 18 | - run: cd ./package && npm ci 19 | - run: cd ./package && npm run build 20 | - run: cd ./package && npm publish 21 | env: 22 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | .vscode/ 107 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphQL OTEL 2 | 3 | ## About 4 | 5 | This package has moved to GraphQL Debugger - 13/09/2023 6 | 7 | - https://github.com/rocket-connect/graphql-debugger 8 | 9 | ## Licence 10 | 11 | MIT Rocket Connect - www.rocketconnect.co.uk 12 | -------------------------------------------------------------------------------- /assets/banner.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/banner.ai -------------------------------------------------------------------------------- /assets/example-patients-fail.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/example-patients-fail.ai -------------------------------------------------------------------------------- /assets/example-patients.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/example-patients.ai -------------------------------------------------------------------------------- /assets/homepage.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/homepage.ai -------------------------------------------------------------------------------- /assets/icons/github-white.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/github-white.ai -------------------------------------------------------------------------------- /assets/icons/mit-icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/mit-icon.ai -------------------------------------------------------------------------------- /assets/icons/npm-white.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/npm-white.ai -------------------------------------------------------------------------------- /assets/icons/otel-icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/otel-icon.ai -------------------------------------------------------------------------------- /assets/icons/rocketconnect-icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/rocketconnect-icon.ai -------------------------------------------------------------------------------- /assets/icons/rocketconnect.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/rocketconnect.ai -------------------------------------------------------------------------------- /assets/icons/typescript-icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/icons/typescript-icon.ai -------------------------------------------------------------------------------- /assets/logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/assets/logo.ai -------------------------------------------------------------------------------- /graphql-otel.com/.env.example: -------------------------------------------------------------------------------- 1 | STATIC_FOLDER="./dist" 2 | HTTP_PORT="4000" 3 | API_URL="http://localhost:4000" 4 | SENDGRID_API_KEY="key" 5 | SENDGRID_FROM="email@email.com" -------------------------------------------------------------------------------- /graphql-otel.com/nginx.nginx: -------------------------------------------------------------------------------- 1 | server { 2 | root /var/www/html; 3 | index index.html index.htm index.nginx-debian.html; 4 | 5 | server_name graphql-otel.com www.graphql-otel.com; 6 | 7 | location / { 8 | proxy_pass http://localhost:4000; 9 | proxy_http_version 1.1; 10 | proxy_set_header Upgrade $http_upgrade; 11 | proxy_set_header Connection 'upgrade'; 12 | proxy_set_header Host $host; 13 | proxy_cache_bypass $http_upgrade; 14 | } 15 | 16 | listen 443 ssl; # managed by Certbot 17 | ssl_certificate /etc/letsencrypt/live/graphql-otel.com/fullchain.pem; # managed by Certbot 18 | ssl_certificate_key /etc/letsencrypt/live/graphql-otel.com/privkey.pem; # managed by Certbot 19 | include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot 20 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot 21 | } 22 | 23 | 24 | server { 25 | if ($host = www.graphql-otel.com) { 26 | return 301 https://$host$request_uri; 27 | } # managed by Certbot 28 | 29 | listen 80 default_server; 30 | listen [::]:80 default_server; 31 | 32 | server_name graphql-otel.com www.graphql-otel.com; 33 | } 34 | 35 | server { 36 | if ($host = graphql-otel.com) { 37 | return 301 https://$host$request_uri; 38 | } # managed by Certbot 39 | 40 | server_name graphql-otel.com www.graphql-otel.com; 41 | listen 80; 42 | return 404; # managed by Certbot 43 | } -------------------------------------------------------------------------------- /graphql-otel.com/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-otel.com", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "cross-env NODE_ENV=development webpack serve", 7 | "server": "node --experimental-modules server.js", 8 | "start": "node --experimental-modules server.js", 9 | "build": "cross-env NODE_ENV=production webpack" 10 | }, 11 | "type": "module", 12 | "dependencies": { 13 | "@sendgrid/mail": "^7.7.0", 14 | "cors": "2.8.5", 15 | "css-loader": "6.7.3", 16 | "express": "4.18.2", 17 | "express-static-gzip": "2.1.7", 18 | "graphql": "16.6.0", 19 | "react": "18.2.0", 20 | "react-dom": "18.2.0", 21 | "react-monaco-editor": "0.51.0" 22 | }, 23 | "devDependencies": { 24 | "@tsconfig/create-react-app": "1.0.2", 25 | "@tsconfig/node18": "1.0.1", 26 | "@types/react": "17.0.39", 27 | "@types/react-dom": "17.0.11", 28 | "@types/webpack": "5.28.0", 29 | "autoprefixer": "10.4.2", 30 | "clean-webpack-plugin": "4.0.0", 31 | "compression-webpack-plugin": "^10.0.0", 32 | "copy-webpack-plugin": "10.2.4", 33 | "cross-env": "7.0.3", 34 | "dotenv": "16.0.0", 35 | "dotenv-webpack": "7.1.0", 36 | "file-loader": "6.2.0", 37 | "html-webpack-plugin": "5.5.0", 38 | "postcss": "8.4.7", 39 | "postcss-loader": "6.2.1", 40 | "style-loader": "3.3.1", 41 | "svg-url-loader": "^8.0.0", 42 | "tailwindcss": "3.0.23", 43 | "terser-webpack-plugin": "5.3.1", 44 | "ts-loader": "9.2.6", 45 | "typescript": "4.6.2", 46 | "url-loader": "4.1.1", 47 | "webpack": "5.69.1", 48 | "webpack-cli": "4.10.0", 49 | "webpack-dev-server": "4.7.4" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /graphql-otel.com/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /graphql-otel.com/public/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/graphql-otel.com/public/banner.png -------------------------------------------------------------------------------- /graphql-otel.com/public/code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /graphql-otel.com/public/example-patients-fail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /graphql-otel.com/public/example-patients.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 27 | 28 | 29 | 30 | 31 | Query patients() 32 | patient.documents() 33 | document.images() 34 | 400ms 35 | 200ms 36 | 100ms 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /graphql-otel.com/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /graphql-otel.com/public/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/graphql-otel.com/public/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /graphql-otel.com/public/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/graphql-otel.com/public/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /graphql-otel.com/public/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/graphql-otel.com/public/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /graphql-otel.com/public/github-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /graphql-otel.com/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /graphql-otel.com/public/mit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/graphql-otel.com/public/mit-icon.png -------------------------------------------------------------------------------- /graphql-otel.com/public/mit-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /graphql-otel.com/public/npm-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /graphql-otel.com/public/otel-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /graphql-otel.com/public/rocket-connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocket-connect/graphql-otel/4d42e741ead69c673e3919a14e047c6cbb4af190/graphql-otel.com/public/rocket-connect.png -------------------------------------------------------------------------------- /graphql-otel.com/public/rocket-connect.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /graphql-otel.com/public/typescript-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /graphql-otel.com/server.js: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | dotenv.config({ path: "./.env" }); 3 | 4 | import express from "express"; 5 | import cors from "cors"; 6 | import expressStaticGzip from "express-static-gzip"; 7 | import sgMail from "@sendgrid/mail"; 8 | 9 | const config = { 10 | STATIC_FOLDER: process.env.STATIC_FOLDER, 11 | HTTP_PORT: process.env.HTTP_PORT, 12 | SENDGRID_API_KEY: process.env.SENDGRID_API_KEY, 13 | SENDGRID_FROM: process.env.SENDGRID_FROM, 14 | }; 15 | 16 | sgMail.setApiKey(config.SENDGRID_API_KEY); 17 | 18 | const app = express(); 19 | app.use(cors()); 20 | app.use(express.json()); 21 | app.post("/contact", async (req, res) => { 22 | const { email, name, message } = req.body; 23 | 24 | const msg = { 25 | to: [email, config.SENDGRID_FROM], 26 | from: config.SENDGRID_FROM, 27 | subject: "GraphQL Tracing with OpenTelemetry", 28 | text: `Hey ${name} ${email}, I'm Dan. Thanks for contacting about support with GraphQL OTEL. We will get back to you shortly. ${message}`, 29 | }; 30 | 31 | try { 32 | await sgMail.send(msg); 33 | } catch (error) { 34 | console.error(error); 35 | } 36 | 37 | res.end(); 38 | }); 39 | 40 | app.use(expressStaticGzip(config.STATIC_FOLDER, {})); 41 | app.get("*", expressStaticGzip(config.STATIC_FOLDER, {})); 42 | app.use("*", expressStaticGzip(config.STATIC_FOLDER, {})); 43 | 44 | function main() { 45 | app.listen(config.HTTP_PORT, (err) => { 46 | if (err) { 47 | console.error(err); 48 | } 49 | 50 | console.log(`Listening at http://localhost:${config.HTTP_PORT}`); 51 | }); 52 | } 53 | 54 | main(); 55 | -------------------------------------------------------------------------------- /graphql-otel.com/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Footer } from "./components/Footer"; 2 | import { GettingStarted } from "./components/GettingStarted"; 3 | import { Header } from "./components/Header"; 4 | import { Intro } from "./components/Intro"; 5 | import { Supported } from "./components/Supported"; 6 | 7 | function App() { 8 | return ( 9 |
10 |
11 | 12 | 13 | 14 |
16 | ); 17 | } 18 | export default App; 19 | -------------------------------------------------------------------------------- /graphql-otel.com/src/components/Contact.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from "react"; 2 | import { API_URL } from "../config"; 3 | 4 | export async function signup(body: { 5 | name: string; 6 | email: string; 7 | message: string; 8 | }) { 9 | const response = await fetch(`${API_URL}/contact`, { 10 | method: "POST", 11 | headers: { 12 | "Content-Type": "application/json", 13 | }, 14 | body: JSON.stringify(body), 15 | }); 16 | 17 | if (response.status !== 200 || !response.ok) { 18 | throw new Error(await response.text()); 19 | } 20 | } 21 | 22 | export function Contact() { 23 | const [error, setError] = useState(""); 24 | const [loading, setLoading] = useState(false); 25 | const [sent, setSent] = useState(false); 26 | 27 | const send = useCallback( 28 | async (e: React.FormEvent) => { 29 | e.preventDefault(); 30 | setLoading(true); 31 | 32 | try { 33 | const body = { 34 | // @ts-ignore 35 | email: e.target.elements.email.value as string, 36 | // @ts-ignore 37 | name: e.target.elements.name.value as string, 38 | // @ts-ignore 39 | message: e.target.elements.message.value as string, 40 | }; 41 | 42 | await signup(body); 43 | setSent(true); 44 | } catch (error) { 45 | const e = error as Error; 46 | setError(e.message); 47 | } finally { 48 | setLoading(false); 49 | } 50 | }, 51 | [setError, setLoading] 52 | ); 53 | 54 | if (error) { 55 | return <>; 56 | } 57 | 58 | return ( 59 |
60 |
61 | 70 | 71 | 80 |