diff --git a/.env.local.example b/.env.local.example index 75cba2b7..04e85011 100644 --- a/.env.local.example +++ b/.env.local.example @@ -41,4 +41,7 @@ HCAPTCHA_SECRET=0x0000000000000000000000000000000000000000 # listmonk LISTMONK_API_USERNAME= -LISTMONK_API_ACCESS_TOKEN= \ No newline at end of file +LISTMONK_API_ACCESS_TOKEN= + +# csat survey JWT secret +CSAT_JWT_SECRET= \ No newline at end of file diff --git a/netlify.toml b/netlify.toml index 6d099d8b..b06a80cc 100644 --- a/netlify.toml +++ b/netlify.toml @@ -37,10 +37,6 @@ from = "/*/support/" to = "/about/" force = true -[[redirects]] - from = "/*/wishlist/" - to = "/about/" - force = true [[redirects]] from = "/*/projects/" to = "/about/who-we-support/" @@ -146,10 +142,6 @@ from = "/support/" to = "/about/" force = true -[[redirects]] - from = "/wishlist/" - to = "/about/" - force = true [[redirects]] from = "/projects/" to = "/about/who-we-support/" diff --git a/package.json b/package.json index 7dfbf53e..098250ca 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,8 @@ "framer-motion": "^11.0.5", "google-spreadsheet": "^3.2.0", "jsforce": "^1.11.0", + "jsonwebtoken": "^9.0.2", + "lucide-react": "^0.546.0", "next": "^14.1.0", "next-sitemap": "^2.5.7", "papaparse": "^5.3.1", @@ -48,6 +50,7 @@ "@types/formidable": "^2.0.4", "@types/google-spreadsheet": "^3.1.5", "@types/jsforce": "^1.9.37", + "@types/jsonwebtoken": "^9.0.10", "@types/mailchimp__mailchimp_marketing": "^3.0.3", "@types/node": "17.0.0", "@types/papaparse": "^5.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99b4f2f4..ff07cced 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -62,6 +62,12 @@ importers: jsforce: specifier: ^1.11.0 version: 1.11.1 + jsonwebtoken: + specifier: ^9.0.2 + version: 9.0.2 + lucide-react: + specifier: ^0.546.0 + version: 0.546.0(react@18.3.1) next: specifier: ^14.1.0 version: 14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -108,6 +114,9 @@ importers: '@types/jsforce': specifier: ^1.9.37 version: 1.11.5 + '@types/jsonwebtoken': + specifier: ^9.0.10 + version: 9.0.10 '@types/mailchimp__mailchimp_marketing': specifier: ^3.0.3 version: 3.0.21 @@ -738,6 +747,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/jsonwebtoken@9.0.10': + resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} + '@types/lodash.mergewith@4.6.6': resolution: {integrity: sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg==} @@ -2058,6 +2070,10 @@ packages: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + jsprim@1.4.2: resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} engines: {node: '>=0.6.0'} @@ -2066,9 +2082,15 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwa@1.4.2: + resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} + jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + jws@4.0.0: resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} @@ -2104,12 +2126,33 @@ packages: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} lodash.mergewith@4.6.2: resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -2124,6 +2167,11 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lucide-react@0.546.0: + resolution: {integrity: sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -3726,6 +3774,11 @@ snapshots: '@types/json5@0.0.29': {} + '@types/jsonwebtoken@9.0.10': + dependencies: + '@types/ms': 2.1.0 + '@types/node': 17.0.0 + '@types/lodash.mergewith@4.6.6': dependencies: '@types/lodash': 4.17.20 @@ -5242,6 +5295,19 @@ snapshots: dependencies: minimist: 1.2.8 + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.7.2 + jsprim@1.4.2: dependencies: assert-plus: 1.0.0 @@ -5256,12 +5322,23 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jwa@1.4.2: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 + jws@3.2.2: + dependencies: + jwa: 1.4.2 + safe-buffer: 5.2.1 + jws@4.0.0: dependencies: jwa: 2.0.1 @@ -5294,10 +5371,24 @@ snapshots: lodash.get@4.4.2: {} + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.merge@4.6.2: {} lodash.mergewith@4.6.2: {} + lodash.once@4.1.1: {} + lodash@4.17.21: {} loose-envify@1.4.0: @@ -5310,6 +5401,10 @@ snapshots: dependencies: yallist: 4.0.0 + lucide-react@0.546.0(react@18.3.1): + dependencies: + react: 18.3.1 + math-intrinsics@1.1.0: {} mdast-util-definitions@5.1.2: diff --git a/public/images/ecosystem-support-logo.png b/public/images/ecosystem-support-logo.png new file mode 100644 index 00000000..b27e4845 Binary files /dev/null and b/public/images/ecosystem-support-logo.png differ diff --git a/public/images/funding-coordination-logo.png b/public/images/funding-coordination-logo.png new file mode 100644 index 00000000..be24bc63 Binary files /dev/null and b/public/images/funding-coordination-logo.png differ diff --git a/public/images/grant-management-logo.png b/public/images/grant-management-logo.png new file mode 100644 index 00000000..f524dd87 Binary files /dev/null and b/public/images/grant-management-logo.png differ diff --git a/public/images/launchpad-logo.png b/public/images/launchpad-logo.png new file mode 100644 index 00000000..80a4749d Binary files /dev/null and b/public/images/launchpad-logo.png differ diff --git a/public/sitemap-0.xml b/public/sitemap-0.xml index c11c4d56..65ca7441 100644 --- a/public/sitemap-0.xml +++ b/public/sitemap-0.xml @@ -1,18 +1,44 @@ -https://esp.ethereum.foundationdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/aboutdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/about/how-we-supportdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/about/who-we-supportdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/academic-grantsdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/academic-grants/applydaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicantsdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicants/office-hoursdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicants/office-hours/applydaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicants/project-grantsdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicants/project-grants/applydaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicants/small-grantsdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/applicants/small-grants/applydaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/devcon-grantsdaily0.72022-06-15T19:25:49.864Z -https://esp.ethereum.foundation/devcon-grants/applydaily0.72022-06-15T19:25:49.864Z +https://esp.ethereum.foundationdaily0.72025-10-17T14:49:03.338Z +https://esp.ethereum.foundation/10-year-anniversarydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/aboutdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/academic-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/academic-grants-2022daily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/academic-grants-2023daily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/academic-grants-2024daily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/account-abstraction-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/office-hoursdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/office-hours/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/rfpdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/rfp/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/wishlistdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/wishlist/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/data-challenge-4844daily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/data-collection-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/devcon-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/devcon-grants/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/epf-application/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/epf-application/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/form-10yoe/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/form-10yoe/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/form-direct/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/form-direct/apply/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/layer-2-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/merge-data-challengedaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/pectra-pgrdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/pse-grants/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/pse-grants/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/pse-sponsorships/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/pse-sponsorships/thank-youdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/run-a-node-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/semaphore-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/zk-grantsdaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/wishlist/a1CVj000003rawTMAQ/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/wishlist/a1CVj000003t5VBMAY/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/wishlist/a1CVj0000043acXMAQ/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/rfp/a1CVj0000041nu1MAA/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/rfp/a1CVj0000042GRNMA2/applydaily0.72025-10-17T14:49:03.339Z +https://esp.ethereum.foundation/applicants/rfp/a1CVj0000042GftMAE/applydaily0.72025-10-17T14:49:03.339Z \ No newline at end of file diff --git a/src/components/ButtonLink.tsx b/src/components/ButtonLink.tsx index 1685956c..579de6a7 100644 --- a/src/components/ButtonLink.tsx +++ b/src/components/ButtonLink.tsx @@ -1,7 +1,6 @@ import { Box, Flex, Link } from '@chakra-ui/react'; import { motion } from 'framer-motion'; import Image from 'next/image'; -import { FC } from 'react'; import { ImportantText } from './UI/headings'; @@ -9,17 +8,18 @@ import { useShadowAnimation } from '../hooks'; import planeVectorSVG from '../../public/images/plane-vector.svg'; -const MotionBox = motion(Box); -const MotionFlex = motion(Flex); +const MotionBox = motion.create(Box); +const MotionFlex = motion.create(Flex); interface Props { label: string; link: string; width: string; + display?: string; isApplyButton?: boolean; } -export const ButtonLink = ({ label, link, width, isApplyButton }: Props) => { +export const ButtonLink = ({ label, link, width, display, isApplyButton }: Props) => { const { shadowBoxControl, setButtonHovered } = useShadowAnimation(); return ( @@ -30,6 +30,7 @@ export const ButtonLink = ({ label, link, width, isApplyButton }: Props) => { h='56px' w={width} position='absolute' + display={display || "flex"} animate={shadowBoxControl} /> @@ -37,9 +38,11 @@ export const ButtonLink = ({ label, link, width, isApplyButton }: Props) => { bg='brand.accent' w={width} py={4} + px={6} justifyContent='center' alignItems='center' position='relative' + display={display || "flex"} _hover={{ bg: 'brand.hover' }} whileHover={{ x: -1.5, y: -1.5 }} onMouseEnter={() => setButtonHovered(true)} diff --git a/src/components/Nav.tsx b/src/components/Nav.tsx index 8c9fa722..3b3d882e 100644 --- a/src/components/Nav.tsx +++ b/src/components/Nav.tsx @@ -26,7 +26,7 @@ import { CloseIcon, HamburgerIcon, NavLinkIcon } from './UI/icons'; import { selectedLink } from '../utils'; -import logoSVG from '../../public/images/esp-logo.svg'; +import GrantManagementLogo from '../../public/images/ecosystem-support-logo.png'; import { ESP_BLOG_URL, ETHEREUM_ORG_URL, HOME_URL, NAV_LINKS } from '../constants'; @@ -43,7 +43,7 @@ export const Nav: FC = () => { sx={isOpen ? { transitionDelay: '0.15s', filter: 'brightness(10)' } : undefined} zIndex={9999} > - Ecosystem Support Program logo + Ecosystem Support Program logo diff --git a/src/components/SubmitButton.tsx b/src/components/SubmitButton.tsx index 8f23ce0d..6d845c39 100644 --- a/src/components/SubmitButton.tsx +++ b/src/components/SubmitButton.tsx @@ -17,8 +17,8 @@ interface Props { text: string; } -const MotionBox = motion(Box); -const MotionButton = motion(Button); +const MotionBox = motion.create(Box); +const MotionButton = motion.create(Button); export const SubmitButton = ({ id = 'submit-application', diff --git a/src/components/UI/HomeAboutCard.tsx b/src/components/UI/HomeAboutCard.tsx index c33ff210..97961a44 100644 --- a/src/components/UI/HomeAboutCard.tsx +++ b/src/components/UI/HomeAboutCard.tsx @@ -16,9 +16,10 @@ interface Props { title: string; link: string; children: ReactNode; + hideLink?: boolean; } -export const HomeAboutCard: FC = ({ bgGradient, img, title, link, children }) => { +export const HomeAboutCard: FC = ({ bgGradient, img, title, link, children, hideLink }) => { const { src, alt, width, height } = img; return ( @@ -55,7 +56,7 @@ export const HomeAboutCard: FC = ({ bgGradient, img, title, link, childre {children} - + diff --git a/src/components/UI/HomepageHero.tsx b/src/components/UI/HomepageHero.tsx index 5d458f5b..86ac33ad 100644 --- a/src/components/UI/HomepageHero.tsx +++ b/src/components/UI/HomepageHero.tsx @@ -30,11 +30,20 @@ export const HomepageHero: FC = () => { textAlign='left' mb={{ base: 6, md: 10 }} > - We provide support to the builders of the Ethereum ecosystem. + We provide support to builders creating public goods for the Ethereum ecosystem. - - + + + diff --git a/src/components/UI/common/SupportTeamCards.tsx b/src/components/UI/common/SupportTeamCards.tsx new file mode 100644 index 00000000..e4a8d3cb --- /dev/null +++ b/src/components/UI/common/SupportTeamCards.tsx @@ -0,0 +1,103 @@ +import { + Flex, + SimpleGrid, + Stack, +} from '@chakra-ui/react'; +import Image from 'next/image'; + +import { ButtonLink } from '../../ButtonLink'; +import { PageSection, PageText } from '../../UI'; + +import communityOrganizersVector from '../../../../public/images/community-organizers-vector.svg'; +import otherGrantProgramsVector from '../../../../public/images/other-grant-programs-vector.svg'; +import researchersVector from '../../../../public/images/researchers-vector.svg'; + +import { FOUNDER_SUCCESS_URL, ENTERPRISE_ACCELERATION_URL, ETHEREUM_EVERYWHERE_URL } from '../../../constants'; + +const SupportTeamCards = () => { + const otherSupportCards = [ + { + title: 'Founders', + description: + "Level up your founder journey with access to programs, mentorship, and visibility across the Ethereum ecosystem.", + ctaLabel: 'Founder Success', + href: FOUNDER_SUCCESS_URL, + icon: { + src: researchersVector, + alt: 'Illustration representing founder success support' + } + }, + { + title: 'Businesses', + description: + 'Explore potential pathways and opportunities for businesses and enterprise looking to leverage Ethereum.', + ctaLabel: 'Enterprise Team', + href: ENTERPRISE_ACCELERATION_URL, + icon: { + src: otherGrantProgramsVector, + alt: 'Building illustration representing business growth' + } + }, + { + title: 'Community Builders', + description: + 'Request support for organizing an event or launching a community initiative.', + ctaLabel: 'Ethereum Everywhere', + href: ETHEREUM_EVERYWHERE_URL, + icon: { + src: communityOrganizersVector, + alt: 'Community illustration representing collaboration' + } + } + ]; + + return ( + + Other EcoDev Teams + + + Looking for different support? Connect with the team that best matches your next step in the ecosystem. + + + {otherSupportCards.map((card) => ( + + + {card.icon.alt} + + + + {card.title} + + + {card.description} + + + + ))} + + + ) +} + +export default SupportTeamCards; \ No newline at end of file diff --git a/src/components/forms/BaseGrantForm.tsx b/src/components/forms/BaseGrantForm.tsx new file mode 100644 index 00000000..c6a7c33b --- /dev/null +++ b/src/components/forms/BaseGrantForm.tsx @@ -0,0 +1,105 @@ +import { Stack, useToast } from '@chakra-ui/react'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { ReactNode } from 'react'; +import { FormProvider, useForm, FieldValues, SubmitHandler, DefaultValues } from 'react-hook-form'; +import { useRouter } from 'next/router'; +import * as z from 'zod'; + +import { TOAST_OPTIONS } from '../../constants'; +import { FormConfig } from './schemas/BaseGrant'; + +interface BaseGrantFormProps { + config: FormConfig; + schema: z.ZodTypeAny; + selectedItem: { + Id: string; + Name: string; + Description__c: string; + }; + onSubmit: (data: T) => Promise; + defaultValues?: Partial; + children?: ReactNode; +} + +export function BaseGrantForm({ + config, + schema, + selectedItem, + onSubmit: submitFunction, + defaultValues = {}, + children +}: BaseGrantFormProps) { + const router = useRouter(); + const toast = useToast(); + + const formDefaultValues: DefaultValues = { + [config.selectedItemIdField]: selectedItem.Id, + ...defaultValues + } as DefaultValues; + + const methods = useForm({ + resolver: zodResolver(schema), + mode: 'all', + shouldFocusError: true, + defaultValues: formDefaultValues + }); + + const { + handleSubmit, + reset, + formState: { errors } + } = methods; + + const onSubmit: SubmitHandler = async data => { + return submitFunction(data) + .then(async res => { + if (res.ok) { + reset(); + + // Parse response to get applicationId and csatToken + try { + const responseData = await res.json(); + const { applicationId, csatToken } = responseData; + + // Navigate to thank you page with applicationId and CSAT token + if (applicationId && csatToken) { + router.push( + `${config.thankYouPageUrl}?applicationId=${applicationId}&csatToken=${csatToken}` + ); + } else { + router.push(config.thankYouPageUrl); + } + } catch (error) { + // If parsing fails, navigate without applicationId + console.error('Error parsing response:', error); + router.push(config.thankYouPageUrl); + } + } else { + toast({ + ...TOAST_OPTIONS, + title: 'Something went wrong while submitting, please try again.', + status: 'error' + }); + throw new Error('Network response was not OK'); + } + }) + .catch(err => console.error('There has been a problem with your operation: ', err.message)); + }; + + return ( + + +
+ {children} +
+
+
+ ); +} diff --git a/src/components/forms/CSATForm.tsx b/src/components/forms/CSATForm.tsx new file mode 100644 index 00000000..3af42c4e --- /dev/null +++ b/src/components/forms/CSATForm.tsx @@ -0,0 +1,168 @@ +import { FC, useState } from 'react'; +import { + Box, + Button, + Circle, + Flex, + Heading, + Textarea, + useToast, + VStack, + HStack, + BoxProps, + Center +} from '@chakra-ui/react'; +import { useForm, FormProvider } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; + +import { CSATSchema, CSATData } from './schemas/CSAT'; +import { api } from './api'; +import { Captcha } from './fields/Captcha'; +import { TOAST_OPTIONS } from '../../constants'; + +interface CSATFormProps extends BoxProps { + applicationId: string; + csatToken: string; +} + +export const CSATForm: FC = ({ applicationId, csatToken, ...props }) => { + const [selectedRating, setSelectedRating] = useState(null); + const toast = useToast(); + + const methods = useForm({ + resolver: zodResolver(CSATSchema), + mode: 'onSubmit', + defaultValues: { + applicationId, + csatToken, + csatRating: undefined, + csatComments: '', + captchaToken: '' + } + }); + + const { + handleSubmit, + register, + setValue, + formState: { isSubmitting, errors } + } = methods; + + const handleRatingClick = (rating: number) => { + setSelectedRating(rating); + setValue('csatRating', rating, { shouldValidate: true }); + }; + + const onSubmit = async (data: CSATData) => { + try { + const res = await api.csat.submit(data); + + if (res.ok) { + toast({ + ...TOAST_OPTIONS, + title: 'Thank you for your feedback!', + description: 'Your response has been recorded.', + status: 'success' + }); + } else { + const errorData = await res.json(); + toast({ + ...TOAST_OPTIONS, + title: 'Unable to submit feedback', + description: errorData.error || 'Please try again later.', + status: 'error' + }); + } + } catch (error) { + console.error('Error submitting CSAT:', error); + toast({ + ...TOAST_OPTIONS, + title: 'Something went wrong', + description: 'Please try again later.', + status: 'error' + }); + } + }; + + return ( + + +
+ + + How satisfied were you with your experience today? + + + {/* Rating Buttons */} + + + {[1, 2, 3, 4, 5].map(rating => ( + handleRatingClick(rating)} + > + {rating} + + ))} + + + {errors.csatRating && ( + + {errors.csatRating.message} + + )} + + + {/* Comments Textarea */} + +