From 324e602df0fc49f8d812bf05dbe4e616c04f3d7e Mon Sep 17 00:00:00 2001 From: jnsdls Date: Wed, 11 Dec 2024 19:45:22 +0000 Subject: [PATCH] closes: DASH-600 (#5700) closes: DASH-600 --- apps/dashboard/framer-rewrites.js | 1 + .../dashboard/src/app/api/contact-us/route.ts | 79 ---- .../dashboard/src/app/api/contact-us/types.ts | 6 - .../src/components/partners/partner-logo.tsx | 121 ------ apps/dashboard/src/page-id.ts | 2 - apps/dashboard/src/pages/contact-us.tsx | 394 ------------------ 6 files changed, 1 insertion(+), 602 deletions(-) delete mode 100644 apps/dashboard/src/app/api/contact-us/route.ts delete mode 100644 apps/dashboard/src/app/api/contact-us/types.ts delete mode 100644 apps/dashboard/src/components/partners/partner-logo.tsx delete mode 100644 apps/dashboard/src/pages/contact-us.tsx diff --git a/apps/dashboard/framer-rewrites.js b/apps/dashboard/framer-rewrites.js index db5e1c58641..776900c4476 100644 --- a/apps/dashboard/framer-rewrites.js +++ b/apps/dashboard/framer-rewrites.js @@ -4,6 +4,7 @@ module.exports = [ "/", "/pricing", "/bounties", + "/contact-us", // -- product landing pages -- // -- connect "/connect", diff --git a/apps/dashboard/src/app/api/contact-us/route.ts b/apps/dashboard/src/app/api/contact-us/route.ts deleted file mode 100644 index d86c86ebd59..00000000000 --- a/apps/dashboard/src/app/api/contact-us/route.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ipAddress } from "@vercel/functions"; -import { type NextRequest, NextResponse } from "next/server"; -import invariant from "tiny-invariant"; -import { cacheGet, cacheSet } from "../../../lib/redis"; -import type { ContactFormPayload } from "./types"; - -// Note: This handler cannot use "edge" runtime because of Redis usage. - -export const POST = async (req: NextRequest) => { - const rateLimitedResponse = await rateLimiter(req); - if (rateLimitedResponse) { - return rateLimitedResponse; - } - - const requestBody = (await req.json()) as ContactFormPayload; - - const { fields } = requestBody; - - invariant(process.env.HUBSPOT_ACCESS_TOKEN, "missing HUBSPOT_ACCESS_TOKEN"); - - const response = await fetch( - "https://api.hsforms.com/submissions/v3/integration/secure/submit/23987964/38849262-3605-4eb2-883b-b4f1aa5ad845", - { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, - }, - method: "POST", - body: JSON.stringify({ fields }), - }, - ); - - if (!response.ok) { - const body = await response.json(); - console.error("error", body); - } - - return NextResponse.json( - { status: response.statusText }, - { - status: response.status, - }, - ); -}; - -async function rateLimiter(req: NextRequest) { - // Max 1 requests per minute - const rateLimitSeconds = 60; - - const ip = - req.headers.get("CF-Connecting-IP") || - ipAddress(req) || - req.headers.get("X-Forwarded-For"); - - if (!ip) { - return NextResponse.json( - { - error: "Could not validate elligibility.", - }, - { status: 400 }, - ); - } - - const cacheKey = `contact-us:${ip}`; - const cacheValue = await cacheGet(cacheKey); - - // if we have a cached value, return an error - if (cacheValue !== null) { - return NextResponse.json( - { - error: `Rate limit exceeded. Try again in ${rateLimitSeconds} seconds.`, - }, - { status: 429 }, - ); - } - - // cache it for `rateLimitSeconds` - await cacheSet(cacheKey, "contact-us-used", rateLimitSeconds); -} diff --git a/apps/dashboard/src/app/api/contact-us/types.ts b/apps/dashboard/src/app/api/contact-us/types.ts deleted file mode 100644 index aaa9f24ee6c..00000000000 --- a/apps/dashboard/src/app/api/contact-us/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type ContactFormPayload = { - fields: { - name: string; - value: string; - }[]; -}; diff --git a/apps/dashboard/src/components/partners/partner-logo.tsx b/apps/dashboard/src/components/partners/partner-logo.tsx deleted file mode 100644 index a29b51c2a4c..00000000000 --- a/apps/dashboard/src/components/partners/partner-logo.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { ChakraNextImage } from "components/Image"; - -const PARTNER_LOGO_MAP = { - rarible: { - img: require("./logos/rarible.png"), - filter: undefined, - }, - aws: { - img: require("./logos/aws.png"), - filter: undefined, - }, - shopify: { - img: require("./logos/shopify.png"), - filter: "grayscale(1)", - }, - paradigm: { - img: require("./logos/paradigm.png"), - filter: undefined, - }, - nyfw: { - img: require("./logos/nyfw.png"), - filter: "brightness(0) invert(1)", - }, - gala_games: { - img: require("./logos/gala_games.png"), - filter: undefined, - }, - mirror: { - img: require("./logos/mirror.png"), - filter: undefined, - }, - layer3: { - img: require("./logos/layer3.png"), - filter: undefined, - }, - animoca: { - img: require("./logos/animoca.png"), - filter: "brightness(0) invert(1)", - }, - pixels: { - img: require("./logos/pixels.png"), - filter: "brightness(0) invert(1)", - }, - coinbase: { - img: require("./logos/coinbase.png"), - filter: undefined, - }, - polygon: { - img: require("./logos/polygon.png"), - filter: undefined, - }, - avacloud: { - img: require("./logos/avacloud.png"), - filter: "grayscale(1)", - }, - infinigods: { - img: require("./logos/infinigods.png"), - filter: "grayscale(1)", - }, - torque: { - img: require("./logos/torque.png"), - filter: undefined, - }, - ztx: { - img: require("./logos/ztx.png"), - filter: undefined, - }, - aavegotchi: { - img: require("./logos/aavegotchi.png"), - filter: undefined, - }, - coolcats: { - img: require("./logos/coolcats.png"), - filter: undefined, - }, - mcfarlane: { - img: require("./logos/mcfarlane.png"), - filter: undefined, - }, - treasure: { - img: require("./logos/treasure.png"), - filter: undefined, - }, - xai: { - img: require("./logos/xai.png"), - filter: undefined, - }, - paima: { - img: require("./logos/paima.png"), - filter: undefined, - }, - myna: { - img: require("./logos/myna.png"), - filter: undefined, - }, -} as const; - -type Partner = keyof typeof PARTNER_LOGO_MAP; - -interface PartnerLogoProps { - partner: Partner; -} -export const PartnerLogo: React.FC = ({ partner }) => { - return ( -
- -
- ); -}; diff --git a/apps/dashboard/src/page-id.ts b/apps/dashboard/src/page-id.ts index 2ccae2d1e0f..bca0b14229a 100644 --- a/apps/dashboard/src/page-id.ts +++ b/apps/dashboard/src/page-id.ts @@ -6,8 +6,6 @@ export enum PageId { // --------------------------------------------------------------------------- // marketing / growth pages // --------------------------------------------------------------------------- - // thirdweb.com/contact-us - ContactUs = "contact-us-page", // thirdweb.com/templates Templates = "templates-page", diff --git a/apps/dashboard/src/pages/contact-us.tsx b/apps/dashboard/src/pages/contact-us.tsx deleted file mode 100644 index 95b75e3c2bd..00000000000 --- a/apps/dashboard/src/pages/contact-us.tsx +++ /dev/null @@ -1,394 +0,0 @@ -import { useForceDarkTheme } from "@/components/theme-provider"; -import { - Box, - Flex, - type FlexProps, - FormControl, - Image, - Input, - List, - Select, - SimpleGrid, -} from "@chakra-ui/react"; -import { HomepageFooter } from "components/footer/Footer"; -import { PartnerLogo } from "components/partners/partner-logo"; -import { HomepageTopNav } from "components/product-pages/common/Topnav"; -import { HomepageSection } from "components/product-pages/homepage/HomepageSection"; -import { useTrack } from "hooks/analytics/useTrack"; -import { ZapIcon } from "lucide-react"; -import { PageId } from "page-id"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; -import { Button, Card, Heading, Text } from "tw-components"; -import type { ThirdwebNextPage } from "utils/types"; -import type { ContactFormPayload } from "../app/api/contact-us/types"; - -interface FormSchema { - firstname: string; - lastname: string; - email: string; - "0-2/name": string; - "0-2/website": string; - jobtitle: string; - "0-2/size_of_company": string; - company_vertical: string; - products: string; - "0-2/when_do_you_expect_to_launch_": string; - how_did_you_hear_about_us_: string; -} - -const TRACKING_CATEGORY = "contact-us"; -const TRACKING_ACTION = "submit-form"; - -const ContactUs: ThirdwebNextPage = () => { - const form = useForm(); - const [formStatus, setFormStatus] = useState< - "idle" | "submitting" | "success" | "error" - >("idle"); - - const trackEvent = useTrack(); - useForceDarkTheme(); - - return ( - - - - - - - Discover how
- - Web3 can 10x
your business. -
-
- - Speak to our team of Web3 experts to
- learn how we can get you shipping faster. -
- - - - - Technical support from real Web3 developers - - - - - - Help figuring out the solution you need - - - - - - Personalized demos of our products and solutions - - - - -
- - { - const payload: ContactFormPayload = { - fields: Object.keys(data).map((key) => ({ - name: key, - value: data[key as keyof FormSchema], - })), - }; - - setFormStatus("submitting"); - - trackEvent({ - category: TRACKING_CATEGORY, - action: TRACKING_ACTION, - label: "attempt", - }); - - try { - const response = await fetch("/api/contact-us", { - method: "POST", - body: JSON.stringify(payload), - }); - - if (!response.ok) { - trackEvent({ - category: TRACKING_CATEGORY, - action: TRACKING_ACTION, - label: "error", - error: "form-submission-failed", - }); - throw new Error("Form submission failed"); - } - - await response.json(); - - trackEvent({ - category: TRACKING_CATEGORY, - action: TRACKING_ACTION, - label: "success", - }); - - setFormStatus("success"); - - form.reset(); - } catch (error) { - trackEvent({ - category: TRACKING_CATEGORY, - action: TRACKING_ACTION, - label: "error", - error: (error as Error).message, - }); - setFormStatus("error"); - } - })} - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {formStatus === "success" && ( - - Thanks for submitting the form. Our team will respond within - 48 hours. - - )} - {formStatus === "error" && ( - - Something went wrong. Please try again. - - )} - - - -
-
- -
- ); -}; - -const TrustedBy: React.FC = (flexProps) => { - return ( - - - Trusted by leading companies - - - - - - - - - - - ); -}; - -ContactUs.pageId = PageId.ContactUs; - -export default ContactUs;